新疆-融邦
1. 委外管理:新增合作商档案、委外订单、往来台账三个页面及接口;合作商附件弹框支持直接上传/删除并即时保存。
2. 信托基金与代储台账:客户档案加「信托基金 / 代储金额」并对超限标红提示;销售台账拆「卖油 / 代储」页签,代储走油库+储罐+合同金额,卖油保留产品明细;台账列表加审批状态与超限红字;审批中心显示销售合同号并能下钻台账明细。
3. 储罐号带入库存:储罐信息表单加「是否启用 / 用途 / 租客信息」联动与校验;库存管理、批号明细、入库/出库表单与列表补齐储罐号、油品、物流、过磅等字段展示。
4. 出库即发货与往来备件:出库台账区分「发货单 / 油品出库」两类来源并分别处理详情;新增备件出入库流水页面。
5. 车辆管理与残油联动:新增车辆管理页面;油品出入库表单物流信息顺序调整,车牌/车挂牌号联动只读。
6. 油品出库联动发货台账:发货台账加「发货单号 / 销售合同号」筛选,修复油品出库行批号列取错字段。
7. 采购申请模块:新增采购申请页面及接口。
8. 付款流水组件:抽出公共「付款流水」弹框组件,采购付款分栏、收付款台账与委外往来台账复用。
9. 列调整:收付款台账删除「付款金额 / 退货金额」;委外往来台账删除「回款金额」,并去掉金额列右对齐。
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // å页æ¥è¯¢è½¦è¾ä¿¡æ¯å表 |
| | | export function listVehicle(query) { |
| | | return request({ |
| | | url: "/basic/vehicle/list", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // æ¥è¯¢å
¨é¨å¯ç¨è½¦è¾ï¼ä¾ä¸æéæ©ï¼ |
| | | export function allVehicle() { |
| | | return request({ |
| | | url: "/basic/vehicle/all", |
| | | method: "get", |
| | | }); |
| | | } |
| | | |
| | | // æ¥è¯¢è½¦è¾è¯¦æ
|
| | | export function getVehicle(id) { |
| | | return request({ |
| | | url: "/basic/vehicle/" + id, |
| | | method: "get", |
| | | }); |
| | | } |
| | | |
| | | // æ°å¢è½¦è¾ |
| | | export function addVehicle(data) { |
| | | return request({ |
| | | url: "/basic/vehicle/add", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // ä¿®æ¹è½¦è¾ |
| | | export function updateVehicle(data) { |
| | | return request({ |
| | | url: "/basic/vehicle/update", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // å é¤è½¦è¾ |
| | | export function delVehicle(ids) { |
| | | return request({ |
| | | url: "/basic/vehicle/del", |
| | | method: "delete", |
| | | data: ids, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | /** |
| | | * å¤ä»¶åºå
¥åºæµæ°´ - å页æ¥è¯¢ |
| | | * params: { current, size, sparePartsId?, direction?, sourceType? } |
| | | * direction: 1=å
¥åº 2=åºåº |
| | | * sourceType: 1=éè´å
¥åº 2=ç»´ä¿®é¢ç¨ 3=ä¿å
»é¢ç¨ |
| | | */ |
| | | export const getSparePartsRecordPage = (params) => { |
| | | return request({ |
| | | url: "/sparePartsRecord/listPage", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å¤ä»¶åºå
¥åºæµæ°´ - æ¹éå é¤ï¼body 为 id æ°ç»ï¼ |
| | | */ |
| | | export const delSparePartsRecord = (ids) => { |
| | | const idList = Array.isArray(ids) ? ids : [ids]; |
| | | return request({ |
| | | url: "/sparePartsRecord/delete", |
| | | method: "delete", |
| | | data: idList, |
| | | }); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | /** 仿¬¾åæ¬¾æµæ°´å页å表 */ |
| | | export function paymentRecordPage(params) { |
| | | return request({ |
| | | url: "/paymentRecord/listPage", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | /** æ°å¢ä»æ¬¾åæ¬¾æµæ°´ */ |
| | | export function addPaymentRecord(data) { |
| | | return request({ |
| | | url: "/paymentRecord/add", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | /** ä¿®æ¹ä»æ¬¾åæ¬¾æµæ°´ */ |
| | | export function updatePaymentRecord(data) { |
| | | return request({ |
| | | url: "/paymentRecord/update", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | /** å é¤ä»æ¬¾åæ¬¾æµæ°´ï¼body 为 id æ°ç»ï¼ */ |
| | | export function delPaymentRecord(ids) { |
| | | const idList = Array.isArray(ids) ? ids : [ids]; |
| | | return request({ |
| | | url: "/paymentRecord/delete", |
| | | method: "delete", |
| | | data: idList, |
| | | }); |
| | | } |
| | |
| | | }) |
| | | } |
| | | |
| | | //åºåºç®¡ç-æ¥è¯¢è§æ ¼åå·ä¸çå¯ç¨æ¹æ¬¡ï¼å¯ç¨é = åºåé - é宿°éï¼ |
| | | export function getBatchNoList(productModelId) { |
| | | return request({ |
| | | url: '/stockmanagement/batchNoList', |
| | | method: 'get', |
| | | params: { productModelId } |
| | | }) |
| | | } |
| | | |
| | | // |
| | |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // æ²¹ååºåºå¯ç¨éæ¥è¯¢ï¼ä¸æ¬¡å©ä½æ²¹é + å½ååºåï¼ |
| | | export const getOilOutAvailableQty = (params) => { |
| | | return request({ |
| | | url: "/stockOutRecord/oilOutAvailableQty", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | // å½å
¥éå®è´§åçå©ä½æ²¹éï¼åªæ´æ° residualOil ä¸åï¼ |
| | | export const updateResidualOil = (id, data) => { |
| | | return request({ |
| | | url: `/stockOutRecord/${id}/residualOil`, |
| | | method: "put", |
| | | data, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // å§å¤è®¢åå页æ¥è¯¢ï¼RuoYi ç»æï¼é¡¶å± rowsï¼ |
| | | export function listOutsourcingOrder(query) { |
| | | return request({ |
| | | url: "/outsourcing/order/list", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // å§å¤è®¢å详æ
ï¼å« productData æç»ï¼ |
| | | export function getOutsourcingOrder(id) { |
| | | return request({ |
| | | url: "/outsourcing/order/getById", |
| | | method: "get", |
| | | params: { id }, |
| | | }); |
| | | } |
| | | |
| | | // æ°å¢å§å¤è®¢åï¼å¼ºå¶èç¨¿ï¼ |
| | | export function addOutsourcingOrder(data) { |
| | | return request({ |
| | | url: "/outsourcing/order/add", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // ä¿®æ¹å§å¤è®¢åï¼ä»
èç¨¿ï¼æç»å
¨éæäº¤ï¼ |
| | | export function editOutsourcingOrder(data) { |
| | | return request({ |
| | | url: "/outsourcing/order/edit", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // å é¤å§å¤è®¢åï¼ä»
è稿ï¼body 为 id æ°ç»ï¼ |
| | | export function delOutsourcingOrder(ids) { |
| | | return request({ |
| | | url: "/outsourcing/order/delete", |
| | | method: "delete", |
| | | data: ids, |
| | | }); |
| | | } |
| | | |
| | | // æäº¤ï¼è稿 -> 已确认ï¼ï¼id 为 query åæ° |
| | | export function submitOutsourcingOrder(id) { |
| | | return request({ |
| | | url: "/outsourcing/order/submit", |
| | | method: "post", |
| | | params: { id }, |
| | | }); |
| | | } |
| | | |
| | | // 宿ï¼å·²ç¡®è®¤ -> å·²å®æï¼ |
| | | export function completeOutsourcingOrder(id) { |
| | | return request({ |
| | | url: "/outsourcing/order/complete", |
| | | method: "post", |
| | | params: { id }, |
| | | }); |
| | | } |
| | | |
| | | // ä½åºï¼è稿/已确认 -> å·²ä½åºï¼ |
| | | export function cancelOutsourcingOrder(id, cancelReason) { |
| | | return request({ |
| | | url: "/outsourcing/order/cancel", |
| | | method: "post", |
| | | params: { id, cancelReason }, |
| | | }); |
| | | } |
| | | |
| | | // 导åºå§å¤è®¢åï¼è¿å Excel æä»¶æµï¼ |
| | | export function exportOutsourcingOrder(query) { |
| | | return request({ |
| | | url: "/outsourcing/order/export", |
| | | method: "post", |
| | | data: query, |
| | | responseType: "blob", |
| | | }); |
| | | } |
| | | |
| | | // æ¥åºåéæå页ï¼åªè¯»ï¼è¿å IPageï¼data.recordsï¼ |
| | | export function scrapStockPage(query) { |
| | | return request({ |
| | | url: "/outsourcing/order/scrapStockPage", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // åä½åæ¡£æ¡å页æ¥è¯¢ï¼è¿å IPageï¼data.recordsï¼ |
| | | export function listPartner(query) { |
| | | return request({ |
| | | url: "/outsourcing/partner/listPage", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // åä½åæ¡£æ¡è¯¦æ
ï¼å« storageBlobVOS éä»¶åæ¾ï¼ |
| | | export function getPartner(id) { |
| | | return request({ |
| | | url: "/outsourcing/partner/" + id, |
| | | method: "get", |
| | | }); |
| | | } |
| | | |
| | | // æ°å¢åä½å |
| | | export function addPartner(data) { |
| | | return request({ |
| | | url: "/outsourcing/partner/add", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // ä¿®æ¹åä½åï¼storageBlobDTOS 为å
¨éè¦çï¼ |
| | | export function updatePartner(data) { |
| | | return request({ |
| | | url: "/outsourcing/partner/update", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // å é¤åä½åï¼body 为 id æ°ç»ï¼ |
| | | export function delPartner(ids) { |
| | | return request({ |
| | | url: "/outsourcing/partner/del", |
| | | method: "delete", |
| | | data: ids, |
| | | }); |
| | | } |
| | | |
| | | // 导åºåä½åï¼è¿å Excel æä»¶æµï¼ |
| | | export function exportPartner(query) { |
| | | return request({ |
| | | url: "/outsourcing/partner/export", |
| | | method: "post", |
| | | data: query, |
| | | responseType: "blob", |
| | | }); |
| | | } |
| | | |
| | | // ä¸è½½å¯¼å
¥æ¨¡æ¿ï¼è¿å Excel æä»¶æµï¼ |
| | | export function downloadPartnerTemplate() { |
| | | return request({ |
| | | url: "/outsourcing/partner/downloadTemplate", |
| | | method: "post", |
| | | responseType: "blob", |
| | | }); |
| | | } |
| | | |
| | | // åä½å䏿é项ï¼ä»
id + partnerNameï¼ |
| | | export function getPartnerOptions() { |
| | | return request({ |
| | | url: "/outsourcing/partner/getOptions", |
| | | method: "get", |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // åä½å徿¥æ±æ»ï¼è¿å IPageï¼data.recordsï¼ |
| | | export function partnerTransactions(query) { |
| | | return request({ |
| | | url: "/outsourcing/report/partnerTransactions", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // åä½å徿¥æç»ï¼é订åï¼è¿å IPageï¼data.recordsï¼ |
| | | // 注æï¼æ¯è¡ paidAmount æ¯åä½å级å计ï¼ä¸æ¯è®¢å级 |
| | | export function partnerTransactionsDetails(partnerId) { |
| | | return request({ |
| | | url: "/outsourcing/report/partnerTransactionsDetails", |
| | | method: "get", |
| | | params: { partnerId }, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // éè´ç³è¯·é¡µé¢æ¥å£ |
| | | import request from "@/utils/request"; |
| | | |
| | | // å页æ¥è¯¢éè´ç³è¯·å表 |
| | | export function applicationList(query) { |
| | | return request({ |
| | | url: "/purchase/application/list", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // æ¥è¯¢éè´ç³è¯·è¯¦æ
ï¼å«äº§åæç»ï¼ |
| | | export function getApplicationById(query) { |
| | | return request({ |
| | | url: "/purchase/application/getById", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // æ°å¢éè´ç³è¯·ï¼èç¨¿ï¼ |
| | | export function addApplication(data) { |
| | | return request({ |
| | | url: "/purchase/application/add", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // ä¿®æ¹éè´ç³è¯· |
| | | export function editApplication(data) { |
| | | return request({ |
| | | url: "/purchase/application/edit", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // å é¤éè´ç³è¯·ï¼æ¯ææ¹éï¼ |
| | | export function delApplication(ids) { |
| | | return request({ |
| | | url: "/purchase/application/delete", |
| | | method: "delete", |
| | | data: ids, |
| | | }); |
| | | } |
| | | |
| | | // éè´ç³è¯·è½¬è®¢åï¼è¿åçæçéè´å°è´¦id |
| | | export function convertToOrder(id) { |
| | | return request({ |
| | | url: "/purchase/application/convertToOrder", |
| | | method: "post", |
| | | params: { id }, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog :model-value="visible" |
| | | :title="title" |
| | | width="60%" |
| | | :close-on-click-modal="false" |
| | | @update:model-value="handleVisibleChange" |
| | | @close="closeDialog"> |
| | | <div class="payment-record-dialog"> |
| | | <div class="dialog-header"> |
| | | <span class="party-name">{{ partyName }}</span> |
| | | <el-button type="primary" |
| | | @click="openAddForm">æ°å¢</el-button> |
| | | </div> |
| | | <el-table :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | height="380px"> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="åçæ¥æ" |
| | | prop="recordDate" |
| | | width="130" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="éé¢(å
)" |
| | | prop="amount" |
| | | width="140" |
| | | show-overflow-tooltip> |
| | | <template #default="{ row }"> |
| | | {{ formatAmount(row.amount) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ¹å¼" |
| | | prop="paymentMethod" |
| | | width="140" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="夿³¨" |
| | | prop="remark" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æä½" |
| | | align="center" |
| | | width="140" |
| | | fixed="right"> |
| | | <template #default="{ row }"> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openEditForm(row)">ç¼è¾</el-button> |
| | | <el-button link |
| | | type="danger" |
| | | @click="handleDelete(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" /> |
| | | </div> |
| | | |
| | | <el-dialog v-model="formVisible" |
| | | :title="form.id ? 'ç¼è¾æµæ°´' : 'æ°å¢æµæ°´'" |
| | | width="500px" |
| | | append-to-body |
| | | :close-on-click-modal="false" |
| | | @close="resetForm"> |
| | | <el-form :model="form" |
| | | label-width="100px" |
| | | :rules="rules" |
| | | ref="formRef"> |
| | | <el-form-item label="åçæ¥æ" |
| | | prop="recordDate"> |
| | | <el-date-picker v-model="form.recordDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | placeholder="è¯·éæ©" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="éé¢(å
)" |
| | | prop="amount"> |
| | | <el-input-number v-model="form.amount" |
| | | :min="0" |
| | | :precision="2" |
| | | :step="0.01" |
| | | placeholder="请è¾å
¥" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¹å¼" |
| | | prop="paymentMethod"> |
| | | <el-input v-model="form.paymentMethod" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨" |
| | | prop="remark"> |
| | | <el-input v-model="form.remark" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="submitForm">确认</el-button> |
| | | <el-button @click="formVisible = false">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, watch, getCurrentInstance } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { |
| | | paymentRecordPage, |
| | | addPaymentRecord, |
| | | updatePaymentRecord, |
| | | delPaymentRecord, |
| | | } from "@/api/financialManagement/paymentRecord.js"; |
| | | |
| | | const props = defineProps({ |
| | | visible: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | title: { |
| | | type: String, |
| | | default: "æ¶ä»æ¬¾æµæ°´", |
| | | }, |
| | | // 1=客æ·ï¼2=ä¾åºå |
| | | partyType: { |
| | | type: [String, Number], |
| | | required: true, |
| | | }, |
| | | partyId: { |
| | | type: [String, Number], |
| | | default: "", |
| | | }, |
| | | partyName: { |
| | | type: String, |
| | | default: "", |
| | | }, |
| | | // 1=仿¬¾ï¼2=忬¾ |
| | | direction: { |
| | | type: [String, Number], |
| | | required: true, |
| | | }, |
| | | }); |
| | | |
| | | const emit = defineEmits(["update:visible", "changed"]); |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const total = ref(0); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | }); |
| | | |
| | | const formVisible = ref(false); |
| | | const formRef = ref(null); |
| | | const form = ref(buildEmptyForm()); |
| | | const rules = { |
| | | recordDate: [{ required: true, message: "è¯·éæ©åçæ¥æ", trigger: "change" }], |
| | | amount: [{ required: true, message: "请è¾å
¥éé¢", trigger: "blur" }], |
| | | }; |
| | | |
| | | function buildEmptyForm() { |
| | | return { |
| | | id: "", |
| | | recordDate: "", |
| | | amount: undefined, |
| | | paymentMethod: "", |
| | | remark: "", |
| | | }; |
| | | } |
| | | |
| | | const formatAmount = amount => { |
| | | return amount ? parseFloat(amount).toFixed(2) : "0.00"; |
| | | }; |
| | | |
| | | const handleVisibleChange = val => { |
| | | emit("update:visible", val); |
| | | }; |
| | | |
| | | const closeDialog = () => { |
| | | page.current = 1; |
| | | tableData.value = []; |
| | | total.value = 0; |
| | | formVisible.value = false; |
| | | }; |
| | | |
| | | const getList = () => { |
| | | if (!props.partyId) { |
| | | tableData.value = []; |
| | | total.value = 0; |
| | | return; |
| | | } |
| | | tableLoading.value = true; |
| | | paymentRecordPage({ |
| | | pageNum: page.current, |
| | | pageSize: page.size, |
| | | partyType: props.partyType, |
| | | partyId: props.partyId, |
| | | direction: props.direction, |
| | | }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | const result = res.data || {}; |
| | | tableData.value = result.records || []; |
| | | total.value = result.total || 0; |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const paginationChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | const openAddForm = () => { |
| | | form.value = buildEmptyForm(); |
| | | formVisible.value = true; |
| | | }; |
| | | |
| | | const openEditForm = row => { |
| | | form.value = { |
| | | id: row.id, |
| | | recordDate: row.recordDate || "", |
| | | amount: row.amount === null || row.amount === undefined ? undefined : Number(row.amount), |
| | | paymentMethod: row.paymentMethod || "", |
| | | remark: row.remark || "", |
| | | }; |
| | | formVisible.value = true; |
| | | }; |
| | | |
| | | const resetForm = () => { |
| | | formRef.value?.resetFields(); |
| | | form.value = buildEmptyForm(); |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | formRef.value?.validate(valid => { |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | const payload = { |
| | | partyType: props.partyType, |
| | | partyId: props.partyId, |
| | | direction: props.direction, |
| | | amount: form.value.amount, |
| | | recordDate: form.value.recordDate || null, |
| | | paymentMethod: form.value.paymentMethod, |
| | | remark: form.value.remark, |
| | | }; |
| | | const isEdit = !!form.value.id; |
| | | const submitRequest = isEdit |
| | | ? updatePaymentRecord({ ...payload, id: form.value.id }) |
| | | : addPaymentRecord(payload); |
| | | submitRequest.then(() => { |
| | | proxy.$modal.msgSuccess(isEdit ? "ä¿®æ¹æå" : "æ°å¢æå"); |
| | | formVisible.value = false; |
| | | getList(); |
| | | emit("changed"); |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | const handleDelete = row => { |
| | | // 该æ¥å£å端æ å½å±æ ¡éªï¼ä»»ä½ç»å½ç¨æ·å¯å ä»»ææµæ°´ï¼æ
确认æ¡å¸¦ä¸æ¥æéé¢å®ä½ |
| | | ElMessageBox.confirm( |
| | | `ç¡®å®å é¤ã${row.recordDate || "æªå¡«æ¥æ"} / ${formatAmount(row.amount)} å
ãè¿æ¡æµæ°´åï¼å é¤åä¸å¯æ¢å¤ã`, |
| | | "å 餿µæ°´", |
| | | { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | } |
| | | ) |
| | | .then(() => { |
| | | delPaymentRecord([row.id]).then(() => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | emit("changed"); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | watch( |
| | | () => props.visible, |
| | | val => { |
| | | if (val) { |
| | | page.current = 1; |
| | | getList(); |
| | | } |
| | | } |
| | | ); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .payment-record-dialog { |
| | | .dialog-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 12px; |
| | | |
| | | .party-name { |
| | | font-size: 15px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination"></PIMTable> |
| | | @pagination="pagination"> |
| | | <template #depositAmountSlot="{ row }"> |
| | | <el-tooltip v-if="row.exceedsTrustFund" |
| | | :content="`代å¨éé¢å计已è¶
åºè¯¥å®¢æ·ä¿¡æåºéï¼ä¿¡æåºéï¼${row.trustFund}ï¼`" |
| | | placement="top"> |
| | | <el-text type="danger">{{ formatAmount(row.depositTotalAmount) }}</el-text> |
| | | </el-tooltip> |
| | | <span v-else>{{ formatAmount(row.depositTotalAmount) }}</span> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | <el-dialog v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢å®¢æ·ä¿¡æ¯' : 'ç¼è¾å®¢æ·ä¿¡æ¯'" |
| | |
| | | :label="dict.label" |
| | | :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¿¡æåºé(å
)ï¼" |
| | | prop="trustFund"> |
| | | <el-input-number v-model="form.trustFund" |
| | | :min="0" |
| | | :precision="2" |
| | | :controls="false" |
| | | placeholder="请è¾å
¥ï¼å¯ä¸ºç©º" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <div class="info-item"> |
| | | <span class="info-label">ä¿¡æåºé(å
)ï¼</span> |
| | | <span class="info-value">{{ formatAmount(detailForm.trustFund) }}</span> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <div class="info-item"> |
| | | <span class="info-label">代å¨éé¢(å
)ï¼</span> |
| | | <span class="info-value" |
| | | :class="{ 'text-danger': detailForm.exceedsTrustFund }"> |
| | | {{ formatAmount(detailForm.depositTotalAmount) }} |
| | | </span> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row v-if="detailForm.exceedsTrustFund" |
| | | :gutter="20"> |
| | | <el-col :span="24"> |
| | | <el-alert type="warning" |
| | | show-icon |
| | | :closable="false" |
| | | :title="`该客æ·ä»£å¨éé¢å计 ${formatAmount(detailForm.depositTotalAmount)} å
ï¼å·²è¶
åºä¿¡æåºé ${formatAmount(detailForm.trustFund)} å
`" /> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | </div> |
| | | <!-- æ´½è°è¿åº¦è®°å½ --> |
| | |
| | | content: [{ required: true, message: "请è¾å
¥å
容", trigger: "blur" }], |
| | | }; |
| | | |
| | | const formatAmount = value => { |
| | | return value === null || value === undefined || value === "" |
| | | ? "-" |
| | | : Number(value).toFixed(2); |
| | | }; |
| | | // 详æ
ç¸å
³ |
| | | const detailDialogVisible = ref(false); |
| | | const detailForm = reactive({ |
| | |
| | | contactPhone: "", |
| | | maintainer: "", |
| | | maintenanceTime: "", |
| | | trustFund: "", |
| | | depositTotalAmount: "", |
| | | exceedsTrustFund: false, |
| | | }); |
| | | const negotiationRecords = ref([]); |
| | | |
| | |
| | | label: "é¶è¡è´¦å·", |
| | | prop: "bankAccount", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "ä¿¡æåºé(å
)", |
| | | prop: "trustFund", |
| | | width: 140, |
| | | formatData: value => |
| | | value === null || value === undefined || value === "" |
| | | ? "-" |
| | | : Number(value).toFixed(2), |
| | | }, |
| | | { |
| | | label: "代å¨éé¢(å
)", |
| | | prop: "depositTotalAmount", |
| | | dataType: "slot", |
| | | slot: "depositAmountSlot", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "弿·è¡å·", |
| | |
| | | bankAccount: "", |
| | | bankCode: "", |
| | | customerType: "", |
| | | // éé¢åæ®µç» null èé ""ï¼é¿å
el-input-number æç©ºä¸²æç®æ 0 |
| | | trustFund: null, |
| | | type: 0 |
| | | }, |
| | | rules: { |
| | |
| | | word-break: break-word; |
| | | } |
| | | |
| | | .text-danger { |
| | | color: var(--el-color-danger); |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .no-records { |
| | | text-align: center; |
| | | padding: 30px; |
| | |
| | | prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¯å¦å¯ç¨ï¼"> |
| | | <el-select v-model="searchForm.isEnabled" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 140px" |
| | | @change="handleQuery"> |
| | | <el-option label="å¯ç¨" |
| | | :value="1" /> |
| | | <el-option label="æªå¯ç¨" |
| | | :value="0" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ç¨éï¼"> |
| | | <el-select v-model="searchForm.usageType" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 140px" |
| | | @change="handleQuery"> |
| | | <el-option label="ç§èµ" |
| | | :value="1" /> |
| | | <el-option label="èªç¨" |
| | | :value="2" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="handleQuery"> æç´¢ |
| | |
| | | <el-table-column label="åºåä½é(m³)" |
| | | prop="remaining" |
| | | min-width="140" /> |
| | | <el-table-column label="æ¯å¦å¯ç¨" |
| | | prop="isEnabled" |
| | | align="center" |
| | | width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.isEnabled === 1 ? 'success' : 'info'" |
| | | size="small"> |
| | | {{ scope.row.isEnabled === 1 ? "å¯ç¨" : "æªå¯ç¨" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç¨é" |
| | | prop="usageType" |
| | | align="center" |
| | | width="90"> |
| | | <template #default="scope"> |
| | | {{ getUsageTypeText(scope.row.usageType) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç§å®¢ä¿¡æ¯" |
| | | prop="tenantInfo" |
| | | min-width="160" |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¯å¦å¯ç¨ï¼" |
| | | prop="isEnabled"> |
| | | <el-switch v-model="form.isEnabled" |
| | | :active-value="1" |
| | | :inactive-value="0" |
| | | active-text="å¯ç¨" |
| | | inactive-text="æªå¯ç¨" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30" |
| | | v-if="form.isEnabled === 1"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç¨éï¼" |
| | | prop="usageType"> |
| | | <el-radio-group v-model="form.usageType"> |
| | | <el-radio :value="1">ç§èµ</el-radio> |
| | | <el-radio :value="2">èªç¨</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" |
| | | v-if="form.usageType === 1"> |
| | | <el-form-item label="ç§å®¢ä¿¡æ¯ï¼" |
| | | prop="tenantInfo"> |
| | | prop="tenantInfo" |
| | | :rules="[ |
| | | { |
| | | required: true, |
| | | message: 'ç§èµçå¨ç½å¿
须填åç§å®¢ä¿¡æ¯', |
| | | trigger: 'blur', |
| | | } |
| | | ]"> |
| | | <el-input v-model="form.tenantInfo" |
| | | placeholder="请è¾å
¥ç§å®¢ä¿¡æ¯" |
| | | clearable /> |
| | |
| | | <script setup> |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { ref, reactive, toRefs, getCurrentInstance } from "vue"; |
| | | import { ref, reactive, toRefs, watch, getCurrentInstance } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { |
| | |
| | | searchForm: { |
| | | tankNo: "", |
| | | category: "", |
| | | isEnabled: "", |
| | | usageType: "", |
| | | }, |
| | | form: { |
| | | id: null, |
| | |
| | | oilProduct: "", |
| | | capacity: null, |
| | | remaining: null, |
| | | isEnabled: 1, |
| | | usageType: null, |
| | | tenantInfo: "", |
| | | }, |
| | | rules: { |
| | |
| | | }, |
| | | }); |
| | | const { searchForm, form, rules } = toRefs(data); |
| | | |
| | | // ç¨éææ¡ï¼1 ç§èµ / 2 èªç¨ |
| | | const getUsageTypeText = value => ({ 1: "ç§èµ", 2: "èªç¨" })[value] || "--"; |
| | | |
| | | // æªå¯ç¨æ¶ç¨éä¸ç§å®¢ä¿¡æ¯ä¸å¾æ¸
空ï¼éèªç¨æ¶ç§å®¢ä¿¡æ¯èªå¨æ¸
空ï¼ç§èµæéè¦ç§å®¢ï¼ |
| | | watch( |
| | | () => [form.value.isEnabled, form.value.usageType], |
| | | () => { |
| | | if (form.value.isEnabled !== 1) { |
| | | form.value.usageType = null; |
| | | form.value.tenantInfo = ""; |
| | | return; |
| | | } |
| | | if (form.value.usageType !== 1) { |
| | | form.value.tenantInfo = ""; |
| | | } |
| | | } |
| | | ); |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | |
| | | selectedRows.value = selection; |
| | | }; |
| | | |
| | | const buildEmptyForm = () => ({ |
| | | id: null, |
| | | tankNo: "", |
| | | category: "", |
| | | oilProduct: "", |
| | | capacity: null, |
| | | remaining: null, |
| | | isEnabled: 1, |
| | | usageType: null, |
| | | tenantInfo: "", |
| | | }); |
| | | |
| | | const openForm = (type, row) => { |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | // å
éç½®åèµå¼ï¼resetFields 伿忮µæåæè½½æ¶çåå¼ï¼æ¾åé¢ä¼æå填好ç弿¸
æ |
| | | proxy.resetForm("formRef"); |
| | | form.value = buildEmptyForm(); |
| | | dialogFormVisible.value = true; |
| | | if (type === "edit" && row) { |
| | | const { id, tankNo, category, oilProduct, capacity, remaining, tenantInfo } = row; |
| | | form.value = { id, tankNo, category, oilProduct, capacity, remaining, tenantInfo }; |
| | | const { |
| | | id, |
| | | tankNo, |
| | | category, |
| | | oilProduct, |
| | | capacity, |
| | | remaining, |
| | | isEnabled, |
| | | usageType, |
| | | tenantInfo, |
| | | } = row; |
| | | form.value = { |
| | | ...buildEmptyForm(), |
| | | id, |
| | | tankNo, |
| | | category, |
| | | oilProduct, |
| | | capacity, |
| | | remaining, |
| | | // å岿°æ®æ²¡æè¯¥å段ï¼ç¼ºå¤±æ¶æãå¯ç¨ãå¤çï¼é¿å
ä¿åæ¶è¢«è¯¯ç½®ä¸ºæªå¯ç¨ |
| | | isEnabled: isEnabled ?? 1, |
| | | usageType: usageType ?? null, |
| | | tenantInfo: tenantInfo ?? "", |
| | | }; |
| | | } |
| | | }; |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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.plateNumber" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="叿ºå§åï¼"> |
| | | <el-input v-model="searchForm.driverName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æï¼"> |
| | | <el-select v-model="searchForm.status" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 160px" |
| | | @change="handleQuery"> |
| | | <el-option label="å¯ç¨" |
| | | value="å¯ç¨" /> |
| | | <el-option label="åç¨" |
| | | value="åç¨" /> |
| | | </el-select> |
| | | </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 type="primary" |
| | | @click="openForm('add')">æ°å¢è½¦è¾</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete()">å é¤ |
| | | </el-button> |
| | | </div> |
| | | <el-table :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | @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="plateNumber" |
| | | min-width="140" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="é»è®¤å¸æº" |
| | | prop="driverName" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="叿ºçµè¯" |
| | | prop="driverPhone" |
| | | min-width="140" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ ¸å®è½½é(å¨)" |
| | | prop="loadCapacity" |
| | | min-width="120" /> |
| | | <el-table-column label="ç¶æ" |
| | | prop="status" |
| | | min-width="90"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.status === 'åç¨' ? 'info' : 'success'" |
| | | size="small"> |
| | | {{ scope.row.status || 'å¯ç¨' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="夿³¨" |
| | | prop="remark" |
| | | min-width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å建æ¶é´" |
| | | prop="createTime" |
| | | min-width="180"> |
| | | <template #default="scope"> |
| | | {{ scope.row.createTime ? scope.row.createTime.replace('T', ' ').slice(0, 19) : '--' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" |
| | | label="æä½" |
| | | width="120" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openForm('edit', scope.row)">ç¼è¾ |
| | | </el-button> |
| | | <el-button link |
| | | type="danger" |
| | | @click="handleDelete([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" /> |
| | | </div> |
| | | <FormDialog v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢è½¦è¾' : 'ç¼è¾è½¦è¾'" |
| | | :width="'40%'" |
| | | :operation-type="operationType" |
| | | @close="closeDia" |
| | | @confirm="submitForm" |
| | | @cancel="closeDia"> |
| | | <el-form :model="form" |
| | | label-width="120px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="车çå·ï¼" |
| | | prop="plateNumber"> |
| | | <el-input v-model="form.plateNumber" |
| | | placeholder="请è¾å
¥è½¦çå·" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç¶æï¼" |
| | | prop="status"> |
| | | <el-select v-model="form.status" |
| | | placeholder="è¯·éæ©" |
| | | style="width: 100%"> |
| | | <el-option label="å¯ç¨" |
| | | value="å¯ç¨" /> |
| | | <el-option label="åç¨" |
| | | value="åç¨" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="é»è®¤å¸æºï¼" |
| | | prop="driverName"> |
| | | <el-input v-model="form.driverName" |
| | | placeholder="请è¾å
¥å¸æºå§å" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="叿ºçµè¯ï¼" |
| | | prop="driverPhone"> |
| | | <el-input v-model="form.driverPhone" |
| | | placeholder="请è¾å
¥11使°å" |
| | | maxlength="11" |
| | | @input="phoneInput" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ ¸å®è½½é(å¨)ï¼" |
| | | prop="loadCapacity"> |
| | | <el-input-number v-model="form.loadCapacity" |
| | | :precision="2" |
| | | :step="1" |
| | | :min="0" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨ï¼" |
| | | prop="remark"> |
| | | <el-input v-model="form.remark" |
| | | type="textarea" |
| | | :rows="2" |
| | | placeholder="请è¾å
¥å¤æ³¨" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { ref, reactive, toRefs, getCurrentInstance } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { |
| | | listVehicle, |
| | | addVehicle, |
| | | updateVehicle, |
| | | delVehicle, |
| | | } from "@/api/basicData/vehicle.js"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | const dialogFormVisible = ref(false); |
| | | const operationType = ref(""); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | }); |
| | | const total = ref(0); |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | plateNumber: "", |
| | | driverName: "", |
| | | status: "", |
| | | }, |
| | | form: { |
| | | id: null, |
| | | plateNumber: "", |
| | | driverName: "", |
| | | driverPhone: "", |
| | | loadCapacity: null, |
| | | status: "å¯ç¨", |
| | | remark: "", |
| | | }, |
| | | rules: { |
| | | plateNumber: [{ required: true, message: "请è¾å
¥è½¦çå·", trigger: "blur" }], |
| | | driverPhone: [ |
| | | { pattern: /^1[3-9]\d{9}$/, message: "请è¾å
¥ææç11使æºå·ç ", trigger: "blur" }, |
| | | ], |
| | | }, |
| | | }); |
| | | const { searchForm, form, rules } = toRefs(data); |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | listVehicle({ ...searchForm.value, ...page }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records || []; |
| | | total.value = res.data.total || 0; |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const paginationChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | |
| | | // çµè¯è¾å
¥éå¶ï¼åªå
许æ°åï¼æå¤11ä½ |
| | | const phoneInput = val => { |
| | | form.value.driverPhone = String(val ?? "") |
| | | .replace(/\D/g, "") |
| | | .slice(0, 11); |
| | | }; |
| | | |
| | | const openForm = (type, row) => { |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = true; |
| | | if (type === "edit" && row) { |
| | | const { id, plateNumber, driverName, driverPhone, loadCapacity, status, remark } = row; |
| | | form.value = { |
| | | id, |
| | | plateNumber, |
| | | driverName, |
| | | driverPhone, |
| | | loadCapacity, |
| | | status: status || "å¯ç¨", |
| | | remark, |
| | | }; |
| | | } else { |
| | | form.value = { |
| | | id: null, |
| | | plateNumber: "", |
| | | driverName: "", |
| | | driverPhone: "", |
| | | loadCapacity: null, |
| | | status: "å¯ç¨", |
| | | remark: "", |
| | | }; |
| | | } |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | const api = form.value.id ? updateVehicle : addVehicle; |
| | | api(form.value).then(() => { |
| | | proxy.$modal.msgSuccess("æä½æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | |
| | | const handleDelete = rows => { |
| | | let ids = []; |
| | | if (rows) { |
| | | ids = rows.map(item => item.id); |
| | | } else if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value.map(item => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm( |
| | | "éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼å»ºè®®ç¨ãåç¨ãä¸çº¿è½¦è¾ï¼å é¤ä¸ä¼æ ¡éªæ¯å¦å·²è¢«åºåºè®°å½å¼ç¨ã", |
| | | "å é¤", |
| | | { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | } |
| | | ) |
| | | .then(() => { |
| | | delVehicle(ids).then(() => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | getList(); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .search_form { |
| | | margin-bottom: 16px; |
| | | } |
| | | </style> |
| | |
| | | <el-form-item label="å¤ä»¶ç¼å·" prop="sparePartsNo"> |
| | | <el-input v-model="form.sparePartsNo"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="产å大类" prop="productId"> |
| | | <el-tree-select |
| | | v-model="form.productId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | | check-strictly |
| | | :data="productOptions" |
| | | :render-after-expand="false" |
| | | @change="handleProductChange" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="è§æ ¼åå·" prop="productModelId"> |
| | | <el-select |
| | | v-model="form.productModelId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in modelOptions" |
| | | :key="item.id" |
| | | :label="item.model" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æ°é" prop="quantity"> |
| | | <el-input type="number" v-model="form.quantity"></el-input> |
| | | </el-form-item> |
| | |
| | | import { ElMessage, ElMessageBox } from 'element-plus'; |
| | | import { getSparePartsList, addSparePart, editSparePart, delSparePart } from "@/api/equipmentManagement/spareParts"; |
| | | import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; |
| | | import { productTreeList, modelList } from "@/api/basicData/product.js"; |
| | | import PIMTable from "@/components/PIMTable/PIMTable.vue"; |
| | | import { getSparePartsUsagePage } from "@/api/equipmentManagement/sparePartsUsage"; |
| | | |
| | |
| | | const operationType = ref('add') |
| | | // 设å¤é项 |
| | | const deviceOptions = ref([]); |
| | | // 产å大类æ /è§æ ¼åå·é项 |
| | | const productOptions = ref([]); |
| | | const modelOptions = ref([]); |
| | | // 表åå¼ç¨ |
| | | const formRef = ref(null); |
| | | // æ¥è¯¢åæ° |
| | |
| | | id:'', |
| | | name: '', |
| | | sparePartsNo: '', |
| | | productId: '', |
| | | productModelId: '', |
| | | status: '', |
| | | description: '', |
| | | deviceLedgerIds: [], |
| | |
| | | } |
| | | }; |
| | | |
| | | // å 载产å大类æ ï¼id -> valueï¼ä¾ el-tree-select 使ç¨ï¼ |
| | | const loadProductOptions = async () => { |
| | | try { |
| | | const res = await productTreeList(); |
| | | productOptions.value = convertIdToValue(Array.isArray(res) ? res : res?.data || []); |
| | | } catch (error) { |
| | | ElMessage.error('è·å产å大类失败'); |
| | | } |
| | | }; |
| | | |
| | | function convertIdToValue(data) { |
| | | return (data || []).map(item => { |
| | | const { id, children, ...rest } = item; |
| | | const newItem = { ...rest, value: id }; |
| | | if (children && children.length > 0) { |
| | | newItem.children = convertIdToValue(children); |
| | | } |
| | | return newItem; |
| | | }); |
| | | } |
| | | |
| | | // åæ¢äº§åå¤§ç±»ï¼æ¸
ç©ºè§æ ¼åå·å¹¶éæ°æåè§æ ¼åå·é项 |
| | | const handleProductChange = async value => { |
| | | form.productModelId = ''; |
| | | modelOptions.value = []; |
| | | if (!value) return; |
| | | try { |
| | | const res = await modelList({ id: value }); |
| | | modelOptions.value = Array.isArray(res) ? res : res?.data || []; |
| | | } catch (error) { |
| | | ElMessage.error('è·åè§æ ¼åå·å¤±è´¥'); |
| | | } |
| | | }; |
| | | |
| | | // æ°å¢åç±» |
| | | const addCategory = async () => { |
| | | await loadDeviceName(); |
| | | await loadProductOptions(); |
| | | form.id = ''; |
| | | form.name = ''; |
| | | form.sparePartsNo = ''; |
| | | form.productId = ''; |
| | | form.productModelId = ''; |
| | | form.status = ''; |
| | | form.description = ''; |
| | | form.deviceLedgerIds = []; |
| | | form.quantity = undefined; |
| | | form.price = null; |
| | | modelOptions.value = []; |
| | | operationType.value = 'add' |
| | | dialogVisible.value = true; |
| | | }; |
| | |
| | | // ç¼è¾åç±» |
| | | const editCategory = async (row) => { |
| | | await loadDeviceName(); |
| | | await loadProductOptions(); |
| | | Object.assign(form, row); |
| | | form.productId = row.productId ?? ''; |
| | | form.productModelId = row.productModelId ?? ''; |
| | | // åæ¾è§æ ¼åå·é项ï¼ç¼è¾æ¶ä¸ä¼è§¦å产å大类 changeï¼ |
| | | if (form.productId) { |
| | | try { |
| | | const res = await modelList({ id: form.productId }); |
| | | modelOptions.value = Array.isArray(res) ? res : res?.data || []; |
| | | } catch (error) { |
| | | modelOptions.value = []; |
| | | } |
| | | } else { |
| | | modelOptions.value = []; |
| | | } |
| | | // 妿å端è¿åçæ¯ deviceIds å符串ï¼éè¦è½¬æ¢ä¸ºæ°ç» |
| | | if (row.deviceIds && typeof row.deviceIds === 'string') { |
| | | // ç¡®ä¿IDç±»åä¸è®¾å¤é项ä¸çIDç±»åä¸è´ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <el-form :inline="true" :model="searchForm"> |
| | | <el-form-item label="å¤ä»¶"> |
| | | <el-select v-model="searchForm.sparePartsId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | | style="width: 240px"> |
| | | <el-option v-for="item in sparePartsOptions" |
| | | :key="item.id" |
| | | :label="item.name" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æ¹å"> |
| | | <el-select v-model="searchForm.direction" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 160px"> |
| | | <el-option label="å
¥åº" :value="1" /> |
| | | <el-option label="åºåº" :value="2" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="æ¥æºç±»å"> |
| | | <el-select v-model="searchForm.sourceType" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 160px"> |
| | | <el-option v-for="item in sourceTypeOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery">æ¥è¯¢</el-button> |
| | | <el-button @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div> |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <el-table :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | @selection-change="handleSelectionChange" |
| | | :row-key="row => row.id" |
| | | height="calc(100vh - 18.5em)"> |
| | | <el-table-column align="center" type="selection" width="55" /> |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column label="å¤ä»¶åç§°" prop="sparePartsName" show-overflow-tooltip /> |
| | | <el-table-column label="æ¹å" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.direction === 1 || row.direction === '1' ? 'success' : 'warning'" |
| | | size="small"> |
| | | {{ getDirectionText(row.direction) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ°é" prop="quantity" width="120" show-overflow-tooltip /> |
| | | <el-table-column label="æ¥æºç±»å" prop="sourceType" width="120" show-overflow-tooltip> |
| | | <template #default="{ row }"> |
| | | {{ getSourceTypeText(row.sourceType) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ¥æºåå·" prop="sourceNo" show-overflow-tooltip /> |
| | | <el-table-column label="夿³¨" prop="remark" show-overflow-tooltip /> |
| | | <el-table-column label="æ¶é´" prop="createTime" width="170" 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 pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { ref, reactive, getCurrentInstance } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { |
| | | getSparePartsRecordPage, |
| | | delSparePartsRecord, |
| | | } from "@/api/equipmentManagement/sparePartsRecord.js"; |
| | | import { getSparePartsList } from "@/api/equipmentManagement/spareParts.js"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | const total = ref(0); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | }); |
| | | const searchForm = ref({ |
| | | sparePartsId: "", |
| | | direction: "", |
| | | sourceType: "", |
| | | }); |
| | | // å¤ä»¶ä¸æé项 |
| | | const sparePartsOptions = ref([]); |
| | | // æ¥æºç±»åæä¸¾ |
| | | const sourceTypeOptions = [ |
| | | { label: "éè´å
¥åº", value: 1 }, |
| | | { label: "ç»´ä¿®é¢ç¨", value: 2 }, |
| | | { label: "ä¿å
»é¢ç¨", value: 3 }, |
| | | ]; |
| | | |
| | | const getDirectionText = direction => { |
| | | const map = { 1: "å
¥åº", 2: "åºåº" }; |
| | | return map[direction] || ""; |
| | | }; |
| | | |
| | | const getSourceTypeText = sourceType => { |
| | | return ( |
| | | sourceTypeOptions.find(item => item.value === sourceType)?.label || "" |
| | | ); |
| | | }; |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | getSparePartsRecordPage({ |
| | | ...searchForm.value, |
| | | current: page.current, |
| | | size: page.size, |
| | | }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | const result = res.data || {}; |
| | | tableData.value = result.records || []; |
| | | total.value = result.total || 0; |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const loadSparePartsOptions = () => { |
| | | getSparePartsList({ current: 1, size: 1000 }) |
| | | .then(res => { |
| | | sparePartsOptions.value = res?.data?.records || []; |
| | | }) |
| | | .catch(() => { |
| | | sparePartsOptions.value = []; |
| | | }); |
| | | }; |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const resetQuery = () => { |
| | | searchForm.value = { |
| | | sparePartsId: "", |
| | | direction: "", |
| | | sourceType: "", |
| | | }; |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const paginationChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection.filter(item => item.id); |
| | | }; |
| | | |
| | | const handleDelete = () => { |
| | | if (selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | delSparePartsRecord(ids).then(() => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | getList(); |
| | | loadSparePartsOptions(); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .search_form { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | justify-content: space-between; |
| | | margin-bottom: 10px; |
| | | } |
| | | </style> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="产å大类" |
| | | <el-form-item label="æ²¹å" |
| | | prop="productName"> |
| | | <el-input v-model="searchForm.productName" |
| | | style="width: 240px" |
| | |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="åºåºä¿¡æ¯" |
| | | align="center" |
| | | :header-cell-style="groupHeaderStyle"> |
| | | <el-table-column label="åºåºæ¹æ¬¡" |
| | | prop="outboundBatches" |
| | | min-width="100" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åºåºæ¥æ" |
| | | prop="createTime" |
| | | prop="outDate" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="产å大类" |
| | | <el-table-column label="åºåºç±»å«" |
| | | prop="outCategory" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ²¹åº" |
| | | prop="oilDepotName" |
| | | min-width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å¨ç½å·" |
| | | prop="tankNo" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ²¹å" |
| | | prop="productName" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åºåºå¨æ°(å¨)" |
| | | prop="outTonnage" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="model" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ¹å·" |
| | | prop="batchNo" |
| | | min-width="140" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åä½" |
| | | prop="unit" |
| | | min-width="70" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åºåºæ°é" |
| | | prop="stockOutNum" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å®é
æ£åæ°é" |
| | | prop="deductQuantity" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å©ä½æ²¹é(å¨)" |
| | | prop="residualOil" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åºåºäºº" |
| | | prop="createBy" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åè´§åå·" |
| | | prop="shippingNo" |
| | | min-width="140" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ¥æº" |
| | | prop="recordType" |
| | | min-width="90" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ getRecordType(scope.row.recordType) }} |
| | |
| | | </el-table-column> |
| | | <el-table-column label="审æ¹ç¶æ" |
| | | prop="approvalStatus" |
| | | min-width="100" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <el-tag :type="getApprovalStatusTagType(scope.row.approvalStatus)" |
| | | size="small"> |
| | | {{ getApprovalStatusLabel(scope.row.approvalStatus) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | <el-table-column label="客æ·ä¿¡æ¯" |
| | | align="center" |
| | | :header-cell-style="groupHeaderStyle"> |
| | | <el-table-column label="客æ·åç§°" |
| | | prop="customerName" |
| | | min-width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="客æ·å¯¹æ¥äºº" |
| | | prop="contactPerson" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="对æ¥äººçµè¯" |
| | | prop="contactPhone" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | </el-table-column> |
| | | <el-table-column label="ç©æµä¿¡æ¯" |
| | | align="center" |
| | | :header-cell-style="groupHeaderStyle"> |
| | | <el-table-column label="叿ºå§å" |
| | | prop="driverName" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="叿ºçµè¯" |
| | | prop="driverPhone" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ¼è¿åå§å" |
| | | prop="escortName" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ¼è¿åçµè¯" |
| | | prop="escortPhone" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="车çå·" |
| | | prop="truckPlateNo" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="车æçå·" |
| | | prop="trailerPlateNo" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | </el-table-column> |
| | | <el-table-column label="è£
æ²¹æä½ä¿¡æ¯" |
| | | align="center" |
| | | :header-cell-style="groupHeaderStyle"> |
| | | <el-table-column label="è£
æ²¹æ£éª" |
| | | prop="loadingInspectionStatus" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="è£
车鹤ä½" |
| | | prop="loadingCranePosition" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å¯åº¦" |
| | | prop="density" |
| | | min-width="80" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="è£
æ²¹æç
§" |
| | | prop="loadingPhotos" |
| | | align="center" |
| | | min-width="90"> |
| | | <template #default="scope"> |
| | | <el-image v-if="toPhotoArray(scope.row.loadingPhotos).length" |
| | | :src="getPhotoUrl(toPhotoArray(scope.row.loadingPhotos)[0])" |
| | | :preview-src-list="getPhotoUrls(scope.row.loadingPhotos)" |
| | | preview-teleported |
| | | fit="cover" |
| | | style="width: 40px; height: 40px; border-radius: 4px" /> |
| | | <span v-else>--</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | <el-table-column label="åºåºè¿ç£
æ°æ®" |
| | | align="center" |
| | | :header-cell-style="groupHeaderStyle"> |
| | | <el-table-column label="æ¯é(å¨)" |
| | | prop="grossWeight" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ç®é(å¨)" |
| | | prop="tareWeight" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åé(å¨)" |
| | | prop="netWeight" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="äºé(å¨)" |
| | | prop="lossQuantity" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å®é
åºåºä½ç§¯(å)" |
| | | prop="actualVolume" |
| | | min-width="130" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ç£
å" |
| | | prop="poundPhotos" |
| | | align="center" |
| | | min-width="90"> |
| | | <template #default="scope"> |
| | | <el-image v-if="toPhotoArray(scope.row.poundPhotos).length" |
| | | :src="getPhotoUrl(toPhotoArray(scope.row.poundPhotos)[0])" |
| | | :preview-src-list="getPhotoUrls(scope.row.poundPhotos)" |
| | | preview-teleported |
| | | fit="cover" |
| | | style="width: 40px; height: 40px; border-radius: 4px" /> |
| | | <span v-else>--</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" |
| | | label="æä½" |
| | | width="110" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-button v-if="isSalesOutRecord(scope.row)" |
| | | link |
| | | type="primary" |
| | | @click="openResidualOil(scope.row)">å½å
¥æ®æ²¹ |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | :limit="page.size" |
| | | @pagination="paginationChange" /> |
| | | </div> |
| | | <!-- æ®æ²¹å½å
¥ï¼éå®è´§ååå¡«å©ä½æ²¹éï¼åªæ´æ° residualOil ä¸å --> |
| | | <el-dialog v-model="residualDialogVisible" |
| | | title="å½å
¥å©ä½æ²¹é" |
| | | width="30%" |
| | | append-to-body> |
| | | <el-form label-width="130px" |
| | | label-position="top"> |
| | | <el-form-item label="åºåºæ¹æ¬¡"> |
| | | <el-input :model-value="residualForm.outboundBatches || '--'" |
| | | readonly /> |
| | | </el-form-item> |
| | | <el-form-item label="车çå·"> |
| | | <el-input :model-value="residualForm.truckPlateNo || '--'" |
| | | readonly /> |
| | | </el-form-item> |
| | | <el-form-item label="åºåºæ°é(å¨)"> |
| | | <el-input :model-value="residualForm.stockOutNum ?? '--'" |
| | | readonly /> |
| | | </el-form-item> |
| | | <el-form-item label="å©ä½æ²¹é(å¨)"> |
| | | <el-input-number v-model="residualForm.residualOil" |
| | | :precision="4" |
| | | :step="1" |
| | | :min="0" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="submitResidualOil">确认</el-button> |
| | | <el-button @click="residualDialogVisible = false">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | delPendingStockOut, |
| | | batchApproveStockOutRecords, |
| | | batchUnapproveStockOutRecords, |
| | | updateResidualOil, |
| | | } from "@/api/inventoryManagement/stockOut.js"; |
| | | import { |
| | | findAllQualifiedStockOutRecordTypeOptions, |
| | |
| | | return "warning"; |
| | | }; |
| | | |
| | | // åç»ç¶è¡¨å¤´æ ·å¼ï¼åºåååç±» |
| | | const groupHeaderStyle = { |
| | | background: "#e8f3ff", |
| | | color: "#1d6fd8", |
| | | fontWeight: "700", |
| | | fontSize: "13px", |
| | | }; |
| | | |
| | | // ç
§çåæ®µå端åçæ¯ JSON å符串ï¼åºåéèªè¡è§£æ |
| | | const toPhotoArray = value => { |
| | | if (!value) { |
| | | return []; |
| | | } |
| | | if (Array.isArray(value)) { |
| | | return value; |
| | | } |
| | | if (typeof value === "string") { |
| | | try { |
| | | const parsed = JSON.parse(value); |
| | | return Array.isArray(parsed) ? parsed : []; |
| | | } catch (e) { |
| | | return []; |
| | | } |
| | | } |
| | | return []; |
| | | }; |
| | | |
| | | const getPhotoUrl = photo => |
| | | typeof photo === "string" ? photo : photo?.url || photo?.previewURL || ""; |
| | | |
| | | // å¾çåï¼åå
¨é¨å°åç¨äºé¢è§ |
| | | const getPhotoUrls = photos => |
| | | toPhotoArray(photos).map(getPhotoUrl).filter(Boolean); |
| | | |
| | | // è·åæ¥æºç±»åé项 |
| | | const fetchStockRecordTypeOptions = () => { |
| | | if (props.type === "0") { |
| | |
| | | |
| | | const expandedRowKeys = ref([]); |
| | | |
| | | // æ®æ²¹å½å
¥ï¼åªå¯¹éå®ç±»åºåºå¼æ¾ï¼æ®æ²¹é¾åªå¯¹ outCategory='éå®' çæï¼ |
| | | const residualDialogVisible = ref(false); |
| | | const residualForm = ref({ |
| | | id: null, |
| | | outboundBatches: "", |
| | | truckPlateNo: "", |
| | | stockOutNum: null, |
| | | residualOil: null, |
| | | }); |
| | | |
| | | const isSalesOutRecord = row => row?.outCategory === "éå®"; |
| | | |
| | | const openResidualOil = row => { |
| | | residualForm.value = { |
| | | id: row.id, |
| | | outboundBatches: row.outboundBatches || "", |
| | | truckPlateNo: row.truckPlateNo || "", |
| | | stockOutNum: row.stockOutNum ?? null, |
| | | residualOil: row.residualOil ?? null, |
| | | }; |
| | | residualDialogVisible.value = true; |
| | | }; |
| | | |
| | | const submitResidualOil = () => { |
| | | const { id, residualOil, stockOutNum } = residualForm.value; |
| | | if (residualOil === null || residualOil === undefined || residualOil === "") { |
| | | proxy.$modal.msgWarning("请è¾å
¥å©ä½æ²¹é"); |
| | | return; |
| | | } |
| | | if (Number(residualOil) < 0) { |
| | | proxy.$modal.msgWarning("å©ä½æ²¹éä¸è½å°äº0"); |
| | | return; |
| | | } |
| | | if ( |
| | | stockOutNum !== null && |
| | | stockOutNum !== undefined && |
| | | Number(residualOil) > Number(stockOutNum) |
| | | ) { |
| | | proxy.$modal.msgWarning("å©ä½æ²¹éä¸è½å¤§äºåºåºæ°é"); |
| | | return; |
| | | } |
| | | updateResidualOil(id, { residualOil }).then(() => { |
| | | proxy.$modal.msgSuccess("å½å
¥æå"); |
| | | residualDialogVisible.value = false; |
| | | getList(); |
| | | }); |
| | | }; |
| | | |
| | | const handleBatchApprove = () => { |
| | | if (selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | |
| | | </div> |
| | | <el-dialog v-model="dialogFormVisible" :title="'æ°å¢åºåº'" width="40%" @close="closeDia"> |
| | | <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> |
| | | <el-form-item label="åºåºæ°éï¼" prop="salesContractNo"> |
| | | <el-form-item label="åºåºæ°éï¼" prop="inboundQuantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.inboundQuantity" placeholder="请è¾å
¥" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="åºåºæ¹æ¬¡ï¼" prop="batchNo"> |
| | | <el-select v-model="form.batchNo" placeholder="è¯·éæ©åºåºæ¹æ¬¡" clearable filterable |
| | | v-loading="batchLoading" style="width: 100%"> |
| | | <el-option v-for="item in batchOptions" :key="item.batchNo" |
| | | :label="`${item.batchNo}ï¼å¯ç¨ ${item.availableQuantity}ï¼`" :value="item.batchNo" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="åºåºæ¥æï¼" prop="projectName"> |
| | | <el-date-picker style="width: 100%" v-model="form.inboundTime" value-format="YYYY-MM-DD" format="YYYY-MM-DD" |
| | |
| | | getStockManagePage, |
| | | delStockManage, |
| | | stockOut, |
| | | getBatchNoList, |
| | | } from "@/api/inventoryManagement/stockManage.js"; |
| | | |
| | | const userStore = useUserStore() |
| | |
| | | rules: { |
| | | inboundTime: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | inboundQuantity: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | batchNo: [{ required: true, message: "è¯·éæ©åºåºæ¹æ¬¡", trigger: "change" }], |
| | | nickname: [{ required: true, message: "è¯·éæ©", trigger: "change" }] |
| | | } |
| | | }) |
| | |
| | | |
| | | const currentRowNum = ref(0) |
| | | const salesLedgerProductId = ref(null); |
| | | const currentRowProductModelId = ref(null) |
| | | // åºåºæ¹æ¬¡å¯é项ï¼å¯ç¨é = åºåé - é宿°éï¼ |
| | | const batchOptions = ref([]) |
| | | const batchLoading = ref(false) |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = async (row) => { |
| | |
| | | currentRowId.value = row.id |
| | | currentRowNum.value = row.inboundNum0 |
| | | salesLedgerProductId.value = row.salesLedgerProductId |
| | | currentRowProductModelId.value = row.productModelId |
| | | form.value = {} |
| | | // åå§åè¡¨åæ°æ® |
| | | form.value = { |
| | | productrecordId: '', |
| | | inboundQuantity: '', // åºåºæ°éæ¸
空 |
| | | batchNo: '', // åºåºæ¹æ¬¡æ¸
空 |
| | | inboundTime: getCurrentDate(), // é»è®¤å½åæ¥æ |
| | | nickName: '', // é»è®¤å½åç¨æ· |
| | | } |
| | | console.log('form',form.value) |
| | | loadBatchOptions() |
| | | // å è½½ç¨æ·å表 |
| | | try { |
| | | const userLists = await userListNoPageByTenantId() |
| | |
| | | } |
| | | } |
| | | |
| | | // å è½½è§æ ¼åå·ä¸çå¯ç¨æ¹æ¬¡ |
| | | const loadBatchOptions = async () => { |
| | | batchOptions.value = [] |
| | | if (!currentRowProductModelId.value) { |
| | | proxy.$modal.msgWarning('å½åè®°å½ç¼ºå°è§æ ¼åå·ï¼æ æ³æ¥è¯¢åºåºæ¹æ¬¡') |
| | | return |
| | | } |
| | | batchLoading.value = true |
| | | try { |
| | | const res = await getBatchNoList(currentRowProductModelId.value) |
| | | batchOptions.value = res.data || [] |
| | | } catch (error) { |
| | | console.error('æ¥è¯¢åºåºæ¹æ¬¡å¤±è´¥:', error) |
| | | } finally { |
| | | batchLoading.value = false |
| | | } |
| | | } |
| | | |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | let num = Number(form.value.inboundQuantity) |
| | | if(num <= 0 || num > currentRowNum.value){ |
| | | return proxy.$modal.msgWarning("请填å
¥æææ°å") |
| | | } |
| | | // åºåææ¹æ¬¡ç®¡çãæ å
è¿å
åºï¼æ°éä¸è½è¶
è¿æéæ¹æ¬¡çå¯ç¨é |
| | | const selectedBatch = batchOptions.value.find( |
| | | item => item.batchNo === form.value.batchNo |
| | | ) |
| | | if (selectedBatch && num > Number(selectedBatch.availableQuantity)) { |
| | | return proxy.$modal.msgWarning( |
| | | `åºåºæ°éä¸è½è¶
è¿æ¹æ¬¡ã${selectedBatch.batchNo}ãçå¯ç¨é ${selectedBatch.availableQuantity}` |
| | | ) |
| | | } |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid && currentRowId.value) { |
| | | const outData = { |
| | | id: currentRowId.value, // åå§è®°å½ID |
| | | type: 2, // 2=éå®åºåºï¼åºåºå³èªå¨çæåè´§å°è´¦ |
| | | salesLedgerProductId: salesLedgerProductId.value, |
| | | productModelId: currentRowProductModelId.value, |
| | | batchNo: form.value.batchNo, // åºåºæ¹æ¬¡ï¼éå®åºåºå¿
å¡«ï¼ |
| | | quantity: form.value.inboundQuantity, // åºåºæ°é |
| | | time: form.value.inboundTime, // åºåºæ¶é´ |
| | | userId: form.value.nickName // æä½äºº |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="产å大类" |
| | | <el-form-item label="æ²¹å" |
| | | prop="productName"> |
| | | <el-input v-model="searchForm.productName" |
| | | style="width: 240px" |
| | |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="å
¥åºä¿¡æ¯" |
| | | align="center" |
| | | :header-cell-style="groupHeaderStyle"> |
| | | <el-table-column label="å
¥åºæ¹æ¬¡" |
| | | prop="inboundBatches" |
| | | width="200" |
| | | min-width="150" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å
¥åºæ¶é´" |
| | | prop="createTime" |
| | | prop="inboundTime" |
| | | min-width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="产å大类" |
| | | <el-table-column label="å
¥åºç±»å«" |
| | | prop="inboundCategory" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ²¹åº" |
| | | prop="oilDepotName" |
| | | min-width="130" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å¨ç½å·" |
| | | prop="tankNo" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ²¹å" |
| | | prop="productName" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ååæ°é(å¨)" |
| | | prop="originalQuantity" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="model" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ¹å·" |
| | | prop="batchNo" |
| | | min-width="140" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åä½" |
| | | prop="unit" |
| | | min-width="70" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å
¥åºæ°é" |
| | | prop="stockInNum" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å
¥åºäºº" |
| | | prop="createBy" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ¥æº" |
| | | prop="recordType" |
| | | min-width="90" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ getRecordType(scope.row.recordType) }} |
| | |
| | | </el-table-column> |
| | | <el-table-column v-if="showSourceOrderNoColumn" |
| | | label="æºåå·" |
| | | width="150" |
| | | min-width="150" |
| | | prop="sourceOrderNo" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | |
| | | </el-table-column> |
| | | <el-table-column label="审æ¹ç¶æ" |
| | | prop="approvalStatus" |
| | | min-width="100" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <el-tag :type="getApprovalStatusTagType(scope.row.approvalStatus)" |
| | |
| | | {{ getApprovalStatusLabel(scope.row.approvalStatus) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | <el-table-column label="客æ·ä¿¡æ¯" |
| | | align="center" |
| | | :header-cell-style="groupHeaderStyle"> |
| | | <el-table-column label="客æ·åç§°" |
| | | prop="customerName" |
| | | min-width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="客æ·å¯¹æ¥äºº" |
| | | prop="contactPerson" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="对æ¥äººçµè¯" |
| | | prop="contactPhone" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | </el-table-column> |
| | | <el-table-column label="ç©æµä¿¡æ¯" |
| | | align="center" |
| | | :header-cell-style="groupHeaderStyle"> |
| | | <el-table-column label="叿ºå§å" |
| | | prop="driverName" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="叿ºçµè¯" |
| | | prop="driverPhone" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ¼è¿åå§å" |
| | | prop="escortName" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ¼è¿åçµè¯" |
| | | prop="escortPhone" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="车çå·" |
| | | prop="truckPlateNo" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="车æçå·" |
| | | prop="trailerPlateNo" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | </el-table-column> |
| | | <el-table-column label="叿²¹æä½ä¿¡æ¯" |
| | | align="center" |
| | | :header-cell-style="groupHeaderStyle"> |
| | | <el-table-column label="车ä½/é
å°æ£éª" |
| | | prop="tankInspectionStatus" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å¸è½¦é¹¤ä½" |
| | | prop="unloadingCranePosition" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å¯åº¦" |
| | | prop="density" |
| | | min-width="80" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="叿²¹æç
§" |
| | | prop="unloadPhotos" |
| | | align="center" |
| | | min-width="90"> |
| | | <template #default="scope"> |
| | | <el-image v-if="toPhotoArray(scope.row.unloadPhotos).length" |
| | | :src="getPhotoUrl(toPhotoArray(scope.row.unloadPhotos)[0])" |
| | | :preview-src-list="getPhotoUrls(scope.row.unloadPhotos)" |
| | | preview-teleported |
| | | fit="cover" |
| | | style="width: 40px; height: 40px; border-radius: 4px" /> |
| | | <span v-else>--</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | <el-table-column label="è¿ç£
æ°æ®" |
| | | align="center" |
| | | :header-cell-style="groupHeaderStyle"> |
| | | <el-table-column label="æ¯é(å¨)" |
| | | prop="grossWeight" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ç®é(å¨)" |
| | | prop="tareWeight" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åé(å¨)" |
| | | prop="netWeight" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="äºé(å¨)" |
| | | prop="lossQuantity" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å®é
å
¥åºä½ç§¯(å)" |
| | | prop="actualVolume" |
| | | min-width="130" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ç£
å" |
| | | prop="poundPhotos" |
| | | align="center" |
| | | min-width="90"> |
| | | <template #default="scope"> |
| | | <el-image v-if="toPhotoArray(scope.row.poundPhotos).length" |
| | | :src="getPhotoUrl(toPhotoArray(scope.row.poundPhotos)[0])" |
| | | :preview-src-list="getPhotoUrls(scope.row.poundPhotos)" |
| | | preview-teleported |
| | | fit="cover" |
| | | style="width: 40px; height: 40px; border-radius: 4px" /> |
| | | <span v-else>--</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination v-show="total > 0" |
| | |
| | | }); |
| | | }; |
| | | |
| | | // åç»ç¶è¡¨å¤´æ ·å¼ï¼åºåååç±» |
| | | const groupHeaderStyle = { |
| | | background: "#e8f3ff", |
| | | color: "#1d6fd8", |
| | | fontWeight: "700", |
| | | fontSize: "13px", |
| | | }; |
| | | |
| | | // ç
§çåæ®µå端åçæ¯ JSON å符串ï¼åºåéèªè¡è§£æ |
| | | const toPhotoArray = value => { |
| | | if (!value) { |
| | | return []; |
| | | } |
| | | if (Array.isArray(value)) { |
| | | return value; |
| | | } |
| | | if (typeof value === "string") { |
| | | try { |
| | | const parsed = JSON.parse(value); |
| | | return Array.isArray(parsed) ? parsed : []; |
| | | } catch (e) { |
| | | return []; |
| | | } |
| | | } |
| | | return []; |
| | | }; |
| | | |
| | | const getPhotoUrl = photo => |
| | | typeof photo === "string" ? photo : photo?.url || photo?.previewURL || ""; |
| | | |
| | | // å¾çåï¼åå
¨é¨å°åç¨äºé¢è§ |
| | | const getPhotoUrls = photos => |
| | | toPhotoArray(photos).map(getPhotoUrl).filter(Boolean); |
| | | |
| | | // è·åæ¥æºç±»åé项 |
| | | const fetchStockRecordTypeOptions = () => { |
| | | if (props.type === "0") { |
| | |
| | | height="100%" |
| | | > |
| | | <el-table-column |
| | | label="产ååç§°" |
| | | label="æ²¹å" |
| | | prop="productName" |
| | | show-overflow-tooltip |
| | | /> |
| | |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="ä¸åæ ¼åºåæ°é" |
| | | prop="unQualifiedQuantity" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="åæ ¼å»ç»æ°é" |
| | | prop="qualifiedLockedQuantity" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="ä¸åæ ¼å»ç»æ°é" |
| | | prop="unQualifiedLockedQuantity" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | |
| | | <el-table-column label="å
¥åºä¿¡æ¯" |
| | | align="center" |
| | | :header-cell-style="groupHeaderStyle"> |
| | | <el-table-column label="æ²¹å" prop="oilProduct" min-width="90" show-overflow-tooltip /> |
| | | <el-table-column label="æ²¹å" prop="productName" min-width="90" show-overflow-tooltip /> |
| | | <el-table-column label="å
¥åºåç§°" prop="oilDepotName" min-width="130" show-overflow-tooltip /> |
| | | <el-table-column label="å
¥åºç±»å«" prop="inboundCategory" min-width="100" show-overflow-tooltip /> |
| | | <el-table-column label="å¨ç½å·" prop="tankNo" min-width="100" show-overflow-tooltip /> |
| | |
| | | <el-table-column label="å¨åºåç§°" prop="outOilDepotName" min-width="130" show-overflow-tooltip /> |
| | | <el-table-column label="å¨ç½å·" prop="outTankNo" min-width="100" show-overflow-tooltip /> |
| | | <el-table-column label="åºåºæ¥æ" prop="outDate" min-width="110" show-overflow-tooltip /> |
| | | <el-table-column label="æ²¹å" prop="outOilProduct" min-width="90" show-overflow-tooltip /> |
| | | <el-table-column label="æ²¹å" prop="productName" min-width="90" show-overflow-tooltip /> |
| | | <el-table-column label="åºåºå¨ä½(å¨)" prop="outTonnage" min-width="110" show-overflow-tooltip /> |
| | | <el-table-column label="客æ·åç§°" prop="outCustomerName" min-width="120" show-overflow-tooltip /> |
| | | <el-table-column label="客æ·å¯¹æ¥äºº" prop="outContactPerson" min-width="100" show-overflow-tooltip /> |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ²¹å" |
| | | prop="oilProduct" |
| | | :rules="isOilProduct ? [ |
| | | { |
| | | required: true, |
| | | message: 'è¯·éæ©æ²¹å', |
| | | trigger: 'change', |
| | | } |
| | | ] : []"> |
| | | <el-input v-if="isOilProduct" |
| | | :model-value="formState.oilProduct" |
| | | :rules="[{ required: true, message: 'è¯·éæ©æ²¹å', trigger: 'change' }]"> |
| | | <el-input :model-value="formState.oilProduct" |
| | | readonly |
| | | placeholder="--" /> |
| | | <el-select v-else |
| | | v-model="formState.oilProduct" |
| | | placeholder="è¯·éæ©" |
| | | disabled |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | import { allOilDepot } from "@/api/basicData/oilDepot.js"; |
| | | import { allTankInfo } from "@/api/basicData/tankInfo.js"; |
| | | import { listCustomer } from "@/api/basicData/customer.js"; |
| | | import { productTreeList } from "@/api/basicData/product.js"; |
| | | |
| | | const props = defineProps({ |
| | | visible: { |
| | |
| | | const oilDepotList = ref([]); |
| | | const tankList = ref([]); |
| | | const customerList = ref([]); |
| | | const oilProductOptions = ref([]); |
| | | |
| | | const isShow = computed({ |
| | | get() { |
| | | return props.visible; |
| | |
| | | emit("update:visible", val); |
| | | }, |
| | | }); |
| | | |
| | | // å¨äº§åæ 䏿¥æ¾"æ²¹å"åç±»èç¹ |
| | | const findOilNode = nodes => { |
| | | for (const node of nodes || []) { |
| | | if (node.productName === "æ²¹å") { |
| | | return node; |
| | | } |
| | | if (node.children && node.children.length) { |
| | | const found = findOilNode(node.children); |
| | | if (found) { |
| | | return found; |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | // æéåååç§°å½ä¸çæ²¹åéé¡¹ï¼æ²¹åèç¹åé¡¹ï¼æ¥èªäº§åç»´æ¤æ¨¡åï¼ |
| | | const matchedOilOption = computed(() => |
| | | oilProductOptions.value.find( |
| | | item => item.productName === formState.value.productName |
| | | ) |
| | | ); |
| | | |
| | | // åªæé䏿²¹ååæ®µé项éæçå
·ä½æ²¹åæå¯ç¨æ²¹ååæ®µï¼"æ²¹å"大类æ¬èº«ä¸å¯ç¨ |
| | | const isOilProduct = computed(() => !!matchedOilOption.value); |
| | | |
| | | // åé(å¨) = æ¯é - ç®é |
| | | const netWeight = computed(() => { |
| | |
| | | formState.value.productModelName = product.model; |
| | | formState.value.productModelId = product.id; |
| | | formState.value.unit = product.unit; |
| | | // æ²¹åé项ä¸åååç§°åæ¥ï¼å½ä¸æ²¹åé项åèªå¨å¸¦åºè¯¥æ²¹åï¼æªå½ä¸åæ¸
空并ç¦ç¨ |
| | | formState.value.oilProduct = matchedOilOption.value |
| | | ? product.productName |
| | | : undefined; |
| | | // æ¬ç§æ·ãæ²¹åãå°±æ¯äº§ååç§°ï¼åºåæç»/åºåºå°è´¦çæ²¹ååç»ç齿¯ productNameï¼ï¼ |
| | | // ç´æ¥åæé产ååï¼ä¸åå»äº§åæ 鿝坹ï¼é¿å
æ¯å¯¹ä¸ä¸æ¶æ²¹åæ ç©ºç½ |
| | | formState.value.oilProduct = product.productName || undefined; |
| | | showProductSelectDialog.value = false; |
| | | // 触å表åéªè¯æ´æ° |
| | | proxy.$refs["formRef"]?.validateField("productModelId"); |
| | |
| | | }); |
| | | listCustomer({ current: 1, size: 1000, type: 0 }).then(res => { |
| | | customerList.value = res?.data?.records || []; |
| | | }); |
| | | productTreeList().then(res => { |
| | | const oilNode = findOilNode(res); |
| | | oilProductOptions.value = oilNode?.children || []; |
| | | }); |
| | | }); |
| | | </script> |
| | |
| | | </el-row> |
| | | <div class="form-section-title">åºåºä¿¡æ¯</div> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-col :span="8"> |
| | | <el-form-item label="åºåºç±»å«" |
| | | prop="outCategory" |
| | | :rules="[{ required: true, message: 'è¯·éæ©åºåºç±»å«', trigger: 'change' }]"> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-col :span="8"> |
| | | <el-form-item label="åºåºæ¹æ¬¡" |
| | | prop="batchNo" |
| | | :rules="isSalesOut |
| | | ? [{ required: true, message: 'éå®ç±»åºåºå¿
须鿩åºåºæ¹æ¬¡', trigger: 'change' }] |
| | | : []"> |
| | | <el-select v-model="formState.batchNo" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | | style="width: 100%"> |
| | | <el-option v-for="item in batchNoOptions" |
| | | :key="item" |
| | | :label="item" |
| | | :value="item" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="å¨åºåç§°" |
| | | prop="oilDepotId" |
| | | :rules="[{ required: true, message: 'è¯·éæ©å¨åºåç§°', trigger: 'change' }]"> |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ²¹å" |
| | | prop="oilProduct" |
| | | :rules="isOilProduct ? [ |
| | | { |
| | | required: true, |
| | | message: 'è¯·éæ©æ²¹å', |
| | | trigger: 'change', |
| | | } |
| | | ] : []"> |
| | | <el-input v-if="isOilProduct" |
| | | :model-value="formState.oilProduct" |
| | | :rules="[{ required: true, message: 'è¯·éæ©æ²¹å', trigger: 'change' }]"> |
| | | <el-input :model-value="formState.oilProduct" |
| | | readonly |
| | | placeholder="--" /> |
| | | <el-select v-else |
| | | v-model="formState.oilProduct" |
| | | placeholder="è¯·éæ©" |
| | | disabled |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | <div class="form-section-title">ç©æµä¿¡æ¯</div> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="车è¾" |
| | | prop="vehicleId" |
| | | :rules="isSalesOut |
| | | ? [{ required: true, message: 'éå®ç±»åºåºå¿
é¡»éæ©è½¦è¾', trigger: 'change' }] |
| | | : []"> |
| | | <el-select v-model="formState.vehicleId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | | popper-class="vehicle-select-popper" |
| | | style="width: 100%" |
| | | @change="vehicleChange"> |
| | | <el-option v-for="item in vehicleList" |
| | | :key="item.id" |
| | | :label="item.plateNumber" |
| | | :value="item.id"> |
| | | <div class="vehicle-option"> |
| | | <div class="vehicle-option-title">{{ item.plateNumber }}</div> |
| | | <div class="vehicle-option-line">é»è®¤å¸æºï¼{{ item.driverName || '--' }}</div> |
| | | <div class="vehicle-option-line">叿ºçµè¯ï¼{{ item.driverPhone || '--' }}</div> |
| | | <div class="vehicle-option-line">æ ¸å®è½½é(å¨)ï¼{{ item.loadCapacity ?? '--' }}</div> |
| | | </div> |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="车æçå·" |
| | | prop="trailerPlateNo" |
| | | :rules="[{ required: true, message: '请è¾å
¥è½¦æçå·', trigger: 'blur' }]"> |
| | | <el-input v-model="formState.trailerPlateNo" |
| | | :readonly="!!formState.vehicleId" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="叿ºå§å" |
| | | prop="driverName" |
| | | :rules="[{ required: true, message: '请è¾å
¥å¸æºå§å', trigger: 'blur' }]"> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="车çå·" |
| | | prop="truckPlateNo" |
| | | :rules="[{ required: true, message: '请è¾å
¥è½¦çå·', trigger: 'blur' }]"> |
| | | <el-input v-model="formState.truckPlateNo" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="车æçå·" |
| | | prop="trailerPlateNo" |
| | | :rules="[{ required: true, message: '请è¾å
¥è½¦æçå·', trigger: 'blur' }]"> |
| | | <el-input v-model="formState.trailerPlateNo" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | <el-row :gutter="30" |
| | | v-if="isSalesOut"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="å¯ç¨é"> |
| | | <div class="available-qty-tip"> |
| | | <span>䏿¬¡å©ä½(å¨)ï¼{{ availableQtyText.lastResidualOil }}</span> |
| | | <span>å½ååºå(å¨)ï¼{{ availableQtyText.stockQuantity }}</span> |
| | | <span class="available-qty-strong">å¯ç¨é(å¨)ï¼{{ availableQtyText.availableQty }}</span> |
| | | <span class="available-qty-rule">å¯ç¨é = 䏿¬¡å©ä½ + å½ååºå</span> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed, getCurrentInstance, onMounted } from "vue"; |
| | | import { ref, computed, watch, getCurrentInstance, onMounted } from "vue"; |
| | | import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue"; |
| | | import ImageUpload from "@/components/AttachmentUpload/image/index.vue"; |
| | | import { addOilOutRecordOnly } from "@/api/inventoryManagement/stockInventory.js"; |
| | | import { |
| | | addOilOutRecordOnly, |
| | | getStockInventoryBatchNoQty, |
| | | } from "@/api/inventoryManagement/stockInventory.js"; |
| | | import { getOilOutAvailableQty } from "@/api/inventoryManagement/stockOut.js"; |
| | | import { allOilDepot } from "@/api/basicData/oilDepot.js"; |
| | | import { allTankInfo } from "@/api/basicData/tankInfo.js"; |
| | | import { allVehicle } from "@/api/basicData/vehicle.js"; |
| | | import { listCustomer } from "@/api/basicData/customer.js"; |
| | | import { productTreeList } from "@/api/basicData/product.js"; |
| | | |
| | | const props = defineProps({ |
| | | visible: { |
| | |
| | | model: "", |
| | | unit: "", |
| | | outCategory: undefined, |
| | | batchNo: undefined, |
| | | oilDepotId: undefined, |
| | | oilDepotName: "", |
| | | tankId: undefined, |
| | |
| | | driverPhone: "", |
| | | escortName: "", |
| | | escortPhone: "", |
| | | vehicleId: undefined, |
| | | truckPlateNo: "", |
| | | trailerPlateNo: "", |
| | | }); |
| | |
| | | const oilDepotList = ref([]); |
| | | const tankList = ref([]); |
| | | const customerList = ref([]); |
| | | const oilProductOptions = ref([]); |
| | | const vehicleList = ref([]); |
| | | const showProductSelectDialog = ref(false); |
| | | // åºåºæ¹æ¬¡åéåè¯¥è§æ ¼çå
¥åºæ¹æ¬¡ |
| | | const batchNoOptions = ref([]); |
| | | // éå®ç±»åºåºçå¯ç¨éæç¤ºï¼ä¸æ¬¡å©ä½ + å½ååºåï¼ |
| | | const availableQty = ref(null); |
| | | |
| | | // å¨äº§åæ 䏿¥æ¾"æ²¹å"åç±»èç¹ |
| | | const findOilNode = nodes => { |
| | | for (const node of nodes || []) { |
| | | if (node.productName === "æ²¹å") { |
| | | return node; |
| | | const fetchBatchNoOptions = () => { |
| | | batchNoOptions.value = []; |
| | | const productModelId = formState.value.productModelId; |
| | | if (!productModelId) { |
| | | return; |
| | | } |
| | | if (node.children && node.children.length) { |
| | | const found = findOilNode(node.children); |
| | | if (found) { |
| | | return found; |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | getStockInventoryBatchNoQty({ |
| | | current: 1, |
| | | size: 200, |
| | | productModelId, |
| | | }).then(res => { |
| | | const records = res?.data?.records || []; |
| | | batchNoOptions.value = [ |
| | | ...new Set(records.map(item => item.batchNo).filter(Boolean)), |
| | | ]; |
| | | }); |
| | | }; |
| | | |
| | | // æéåååç§°å½ä¸çæ²¹åéé¡¹ï¼æ²¹åèç¹åé¡¹ï¼æ¥èªäº§åç»´æ¤æ¨¡åï¼ |
| | | const matchedOilOption = computed(() => |
| | | oilProductOptions.value.find( |
| | | item => item.productName === formState.value.productName |
| | | ) |
| | | ); |
| | | // éå®ç±»åºåºå¿
é¡»ç»åºåºæ¹æ¬¡ï¼å端æ°å¢æ¶å³æ ¡éªï¼ä¸å®¡æ¹éè¿ä¼ææ¹æ¬¡æ£åºåï¼ |
| | | const isSalesOut = computed(() => formState.value.outCategory === "éå®"); |
| | | |
| | | // åªæé䏿²¹ååæ®µé项éæçå
·ä½æ²¹åæå¯ç¨æ²¹ååæ®µï¼"æ²¹å"大类æ¬èº«ä¸å¯ç¨ |
| | | const isOilProduct = computed(() => !!matchedOilOption.value); |
| | | // å¯ç¨éæç¤ºï¼è½¦è¾ + è§æ ¼ï¼+æ¹æ¬¡ï¼ç¡®å®ååå端åã䏿¬¡å©ä½ / å½ååºå / å¯ç¨éã |
| | | const fetchAvailableQty = () => { |
| | | availableQty.value = null; |
| | | const { vehicleId, productModelId, batchNo } = formState.value; |
| | | if (!isSalesOut.value || !vehicleId || !productModelId) { |
| | | return; |
| | | } |
| | | getOilOutAvailableQty({ vehicleId, productModelId, batchNo }) |
| | | .then(res => { |
| | | availableQty.value = res?.data || null; |
| | | }) |
| | | .catch(() => { |
| | | availableQty.value = null; |
| | | }); |
| | | }; |
| | | |
| | | const availableQtyText = computed(() => ({ |
| | | lastResidualOil: availableQty.value?.lastResidualOil ?? "--", |
| | | stockQuantity: availableQty.value?.stockQuantity ?? "--", |
| | | availableQty: availableQty.value?.availableQty ?? "--", |
| | | })); |
| | | |
| | | watch( |
| | | () => [ |
| | | formState.value.outCategory, |
| | | formState.value.vehicleId, |
| | | formState.value.productModelId, |
| | | formState.value.batchNo, |
| | | ], |
| | | () => { |
| | | fetchAvailableQty(); |
| | | } |
| | | ); |
| | | |
| | | const isShow = computed({ |
| | | get() { |
| | |
| | | formState.value.model = product.model; |
| | | formState.value.productModelId = product.id; |
| | | formState.value.unit = product.unit; |
| | | // æ²¹åé项ä¸åååç§°åæ¥ï¼å½ä¸æ²¹åé项åèªå¨å¸¦åºè¯¥æ²¹åï¼æªå½ä¸åæ¸
空并ç¦ç¨ |
| | | formState.value.oilProduct = matchedOilOption.value |
| | | ? product.productName |
| | | : undefined; |
| | | // æ¬ç§æ·ãæ²¹åãå°±æ¯äº§ååç§°ï¼åºåæç»/åºåºå°è´¦çæ²¹ååç»ç齿¯ productNameï¼ï¼ |
| | | // ç´æ¥åæé产ååï¼ä¸åå»äº§åæ 鿝坹ï¼é¿å
æ¯å¯¹ä¸ä¸æ¶æ²¹åæ ç©ºç½ |
| | | formState.value.oilProduct = product.productName || undefined; |
| | | formState.value.batchNo = undefined; |
| | | fetchBatchNoOptions(); |
| | | showProductSelectDialog.value = false; |
| | | proxy.$refs["formRef"]?.validateField("productModelId"); |
| | | } |
| | |
| | | } |
| | | }; |
| | | |
| | | // 车è¾éæ©æ¹åï¼è½¦çå·ã车æçå·ä¸å¸æºä¿¡æ¯ç±è½¦è¾ä¸»æ°æ®å¸¦åºï¼åºåºæ¶å¸æºå¯æå¨è¦ç |
| | | const vehicleChange = id => { |
| | | const vehicle = vehicleList.value.find(item => item.id === id); |
| | | if (vehicle) { |
| | | formState.value.truckPlateNo = vehicle.plateNumber || ""; |
| | | // 车æçå·ä¸è½¦çå·æ¯åä¸ä¸ªçï¼éäºè½¦è¾å°±å¸¦åºå¹¶ç½®ä¸ºåªè¯»ï¼é¿å
æå¡«åºä¸¤ä¸ªä¸ä¸è´çå¼ |
| | | formState.value.trailerPlateNo = vehicle.plateNumber || ""; |
| | | formState.value.driverName = vehicle.driverName || ""; |
| | | formState.value.driverPhone = vehicle.driverPhone || ""; |
| | | } else { |
| | | formState.value.truckPlateNo = ""; |
| | | formState.value.trailerPlateNo = ""; |
| | | } |
| | | }; |
| | | |
| | | const handleSubmit = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | |
| | | allOilDepot().then(res => { |
| | | oilDepotList.value = res?.data || []; |
| | | }); |
| | | productTreeList().then(res => { |
| | | const oilNode = findOilNode(res); |
| | | oilProductOptions.value = oilNode?.children || []; |
| | | }); |
| | | allTankInfo().then(res => { |
| | | tankList.value = res?.data || []; |
| | | }); |
| | | listCustomer({ current: 1, size: 1000, type: 0 }).then(res => { |
| | | customerList.value = res?.data?.records || []; |
| | | }); |
| | | allVehicle().then(res => { |
| | | vehicleList.value = res?.data || []; |
| | | }); |
| | | }); |
| | | </script> |
| | |
| | | } |
| | | |
| | | .tank-option-line { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | line-height: 1.8; |
| | | } |
| | | } |
| | | |
| | | // å¯ç¨éæç¤ºï¼ä¸æ¬¡å©ä½ + å½ååºå = å¯ç¨é |
| | | .available-qty-tip { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | gap: 6px 20px; |
| | | width: 100%; |
| | | padding: 6px 14px; |
| | | font-size: 13px; |
| | | color: #303133; |
| | | background: rgba(64, 158, 255, 0.08); |
| | | border-left: 3px solid #409eff; |
| | | border-radius: 3px; |
| | | |
| | | .available-qty-strong { |
| | | font-weight: 600; |
| | | color: #1d6fd8; |
| | | } |
| | | |
| | | .available-qty-rule { |
| | | color: #909399; |
| | | } |
| | | } |
| | | |
| | | // 车è¾ä¸æé项ï¼å°å¡çæ ·å¼ |
| | | .vehicle-option { |
| | | padding: 8px 10px; |
| | | |
| | | .vehicle-option-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .vehicle-option-line { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | line-height: 1.8; |
| | |
| | | } |
| | | } |
| | | |
| | | // 车è¾ä¸æé¢æ¿ï¼body ä¸ï¼éå
¨å±æ ·å¼ï¼ |
| | | .vehicle-select-popper { |
| | | .el-select-dropdown__item { |
| | | height: auto; |
| | | line-height: normal; |
| | | padding: 4px 0; |
| | | } |
| | | |
| | | .vehicle-option { |
| | | border: 1px solid #e4e7ed; |
| | | border-radius: 6px; |
| | | background-color: #fafbfc; |
| | | |
| | | &:hover { |
| | | border-color: #409eff; |
| | | background-color: #f0f7ff; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 客æ·åç§°ä¸æé¢æ¿ï¼body ä¸ï¼éå
¨å±æ ·å¼ï¼ |
| | | .customer-select-popper { |
| | | .el-select-dropdown__item { |
| | |
| | | <div class="search_form mb10"> |
| | | <el-form ref="searchFormRef" |
| | | :model="searchForm" |
| | | class="demo-form-inline"> |
| | | class="demo-form-inline" |
| | | style="width: 100%"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="4"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="产å大类" |
| | | prop="productName"> |
| | | <el-input v-model="searchForm.productName" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="è§æ ¼åå·" |
| | | prop="model"> |
| | | <el-input v-model="searchForm.model" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="æ¹å·" |
| | | prop="batchNo"> |
| | | <el-input v-model="searchForm.batchNo" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <!-- æé® --> |
| | | <el-col :span="4"> |
| | | <el-col :span="6"> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="getList"> |
| | |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <div style="display: flex; gap: 10px; flex-wrap: nowrap;"> |
| | | </div> |
| | | <div class="table_list"> |
| | | <div class="actions"> |
| | | <div></div> |
| | | <div> |
| | | <el-button type="primary" |
| | | @click="isShowNewModal = true">æ°å¢åºå</el-button> |
| | | <el-button type="primary" |
| | |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <el-table :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | |
| | | :row-key="(row, index) => index" |
| | | style="width: 100%" |
| | | :row-class-name="tableRowClassName" |
| | | height="calc(100vh - 18.5em)"> |
| | | :span-method="spanMethod" |
| | | height="calc(100vh - 21em)"> |
| | | <el-table-column align="center" |
| | | type="selection" |
| | | :selectable="isRowSelectable" |
| | | width="55" /> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | :index="indexMethod" |
| | | width="60" /> |
| | | <el-table-column label="产ååç§°" |
| | | prop="productName" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | min-width="120"> |
| | | <template #default="scope"> |
| | | <div v-if="scope.row.__isGroup" |
| | | class="tank-group-band"> |
| | | <span class="tank-group-band__name">å¨ç½å· {{ scope.row.tankNo || "æªåé
" }}</span> |
| | | <span class="tank-group-band__stat">åæ ¼ {{ scope.row.qualifiedQuantity }}</span> |
| | | <span class="tank-group-band__stat">å»ç» {{ scope.row.qualifiedLockedQuantity }}</span> |
| | | </div> |
| | | <span v-else>{{ scope.row.productName }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="model" |
| | | min-width="120" |
| | |
| | | prop="batchNo" |
| | | min-width="150" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å¨ç½å·" |
| | | prop="tankNo" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åæ ¼åºåæ°é" |
| | | prop="qualifiedQuantity" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ä¸åæ ¼åºåæ°é" |
| | | prop="unQualifiedQuantity" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åæ ¼å»ç»æ°é" |
| | | prop="qualifiedLockedQuantity" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ä¸åæ ¼å»ç»æ°é" |
| | | prop="unQualifiedLockedQuantity" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åºåé¢è¦æ°é" |
| | | prop="warnNum" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="夿³¨" |
| | | prop="remark" |
| | | min-width="150" |
| | | show-overflow-tooltip /> |
| | | <!-- <el-table-column label="夿³¨"--> |
| | | <!-- prop="remark"--> |
| | | <!-- min-width="150"--> |
| | | <!-- show-overflow-tooltip />--> |
| | | <el-table-column label="æè¿æ´æ°æ¶é´" |
| | | prop="updateTime" |
| | | min-width="160" |
| | |
| | | |
| | | <script setup> |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { ref, reactive, toRefs, onMounted, getCurrentInstance } from "vue"; |
| | | import { ref, reactive, toRefs, computed, onMounted, getCurrentInstance } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { getStockInventoryListPageCombined } from "@/api/inventoryManagement/stockInventory.js"; |
| | | const props = defineProps({ |
| | |
| | | type: Number, |
| | | required: true, |
| | | default: 0, |
| | | }, |
| | | productName: { |
| | | type: String, |
| | | default: "", |
| | | }, |
| | | }); |
| | | |
| | |
| | | size: 100, |
| | | }); |
| | | const total = ref(0); |
| | | // å¨ç½å·åç±»è¡å 满æ´è¡ï¼æç»è¡æ£å¸¸æ¸²æ |
| | | const TABLE_COLUMN_COUNT = 13; |
| | | const GROUP_ROW_LEAD_COLUMNS = 2; // éæ©å + åºå·å |
| | | const isRowSelectable = row => !row?.__isGroup; |
| | | // åªææåãåæä¸¤ç±»ä¼æå¨ç½åç½åæ¾ï¼å
¶ä½å¤§ç±»ä¸åå¨ç½å·åç» |
| | | const TANK_GROUP_CATEGORIES = ["æå", "åæ"]; |
| | | const shouldGroupByTank = computed(() => |
| | | TANK_GROUP_CATEGORIES.includes(props.productName) |
| | | ); |
| | | const sumBy = (rows, key) => |
| | | rows.reduce((acc, row) => acc + Number(row[key] || 0), 0); |
| | | const buildGroupedRows = rows => { |
| | | const groups = new Map(); |
| | | rows.forEach(row => { |
| | | const tankNo = row.tankNo || ""; |
| | | if (!groups.has(tankNo)) { |
| | | groups.set(tankNo, []); |
| | | } |
| | | groups.get(tankNo).push(row); |
| | | }); |
| | | const sortedTankNos = [...groups.keys()].sort((a, b) => { |
| | | if (!a) return 1; |
| | | if (!b) return -1; |
| | | return a.localeCompare(b, "zh-CN", { numeric: true }); |
| | | }); |
| | | return sortedTankNos.flatMap(tankNo => { |
| | | const groupRows = groups.get(tankNo); |
| | | return [ |
| | | { |
| | | __isGroup: true, |
| | | tankNo, |
| | | qualifiedQuantity: sumBy(groupRows, "qualifiedQuantity"), |
| | | qualifiedLockedQuantity: sumBy(groupRows, "qualifiedLockedQuantity"), |
| | | }, |
| | | ...groupRows, |
| | | ]; |
| | | }); |
| | | }; |
| | | const spanMethod = ({ row, columnIndex }) => { |
| | | if (!row?.__isGroup) { |
| | | return { rowspan: 1, colspan: 1 }; |
| | | } |
| | | if (columnIndex === 0) { |
| | | return { rowspan: 1, colspan: GROUP_ROW_LEAD_COLUMNS }; |
| | | } |
| | | if (columnIndex === GROUP_ROW_LEAD_COLUMNS) { |
| | | return { |
| | | rowspan: 1, |
| | | colspan: TABLE_COLUMN_COUNT - GROUP_ROW_LEAD_COLUMNS, |
| | | }; |
| | | } |
| | | return { rowspan: 0, colspan: 0 }; |
| | | }; |
| | | // åºå·åªå¯¹æç»è¡è¿ç»ç¼å·ï¼åç±»è¡ç空 |
| | | const indexMethod = index => { |
| | | if (tableData.value[index]?.__isGroup) { |
| | | return ""; |
| | | } |
| | | let count = 0; |
| | | for (let i = 0; i <= index; i++) { |
| | | if (!tableData.value[i]?.__isGroup) { |
| | | count += 1; |
| | | } |
| | | } |
| | | return count; |
| | | }; |
| | | // æ¯å¦æ¾ç¤ºæ°å¢å¼¹æ¡ |
| | | const isShowNewModal = ref(false); |
| | | // æ¯å¦æ¾ç¤ºæ²¹åå
¥åºå¼¹æ¡ |
| | |
| | | getStockInventoryListPageCombined({ ...searchForm.value, ...page }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | tableData.value = shouldGroupByTank.value |
| | | ? buildGroupedRows(res.data.records) |
| | | : res.data.records; |
| | | total.value = res.data.total; |
| | | // æ°æ®å è½½å®æåæ£æ¥åºå |
| | | // checkStockAndCreatePurchase(); |
| | |
| | | |
| | | // è¡¨æ ¼è¡ç±»å |
| | | const tableRowClassName = ({ row }) => { |
| | | if (row?.__isGroup) { |
| | | return "row-tank-group"; |
| | | } |
| | | const stock = Number(row?.qualifiedUnLockedQuantity ?? 0); |
| | | const warn = Number(row?.warnNum ?? 0); |
| | | if (!Number.isFinite(stock) || !Number.isFinite(warn)) { |
| | |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .actions { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | :deep(.row-low-stock td) { |
| | | background-color: #fde2e2; |
| | | color: #c45656; |
| | |
| | | :deep(.row-low-stock:hover > td) { |
| | | background-color: #fcd4d4; |
| | | } |
| | | |
| | | :deep(.row-tank-group > td) { |
| | | background-color: #eef5ff; |
| | | } |
| | | |
| | | :deep(.row-tank-group:hover > td) { |
| | | background-color: #e4eefc; |
| | | } |
| | | |
| | | :deep(.tank-group-band) { |
| | | display: flex; |
| | | align-items: center; |
| | | width: 100%; |
| | | font-size: 13px; |
| | | line-height: 20px; |
| | | } |
| | | |
| | | :deep(.tank-group-band__name) { |
| | | margin-right: auto; |
| | | padding-left: 8px; |
| | | border-left: 3px solid #1d6fd8; |
| | | font-weight: 700; |
| | | color: #1d6fd8; |
| | | } |
| | | |
| | | :deep(.tank-group-band__stat) { |
| | | margin-left: 24px; |
| | | font-weight: 600; |
| | | color: #3a7bd5; |
| | | } |
| | | </style> |
| | |
| | | :label="tab.productName" |
| | | :name="tab.id" |
| | | :key="tab.id"> |
| | | <Record :product-id="tab.id" v-if="tab.id === activeTab" /> |
| | | <Record :product-id="tab.id" :product-name="tab.productName" v-if="tab.id === activeTab" /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | </div> |
| | |
| | | purchaseContractNumber: row.purchaseContractNumber || "", |
| | | quotationNo: row.quotationNo || "", |
| | | shippingNo: row.shippingNo || "", |
| | | salesContractNo: row.salesContractNo || "", |
| | | }; |
| | | } |
| | | |
| | |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <!-- éå®å°è´¦å®¡æ¹è¯¦æ
ï¼åæ²¹ / 代å¨ï¼ --> |
| | | <template v-else-if="row.businessType === 19"> |
| | | <div v-if="detailData && Object.keys(detailData).length" class="sales-ledger-detail"> |
| | | <el-divider content-position="left">éå®å°è´¦è¯¦æ
</el-divider> |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions-item label="éå®ååå·">{{ detailData.salesContractNo || "--" }}</el-descriptions-item> |
| | | <el-descriptions-item label="éå®ç±»å">{{ detailData.ledgerType || "--" }}</el-descriptions-item> |
| | | <el-descriptions-item label="客æ·åç§°">{{ detailData.customerName || "--" }}</el-descriptions-item> |
| | | <el-descriptions-item label="ä¸å¡å">{{ detailData.salesman || "--" }}</el-descriptions-item> |
| | | <el-descriptions-item label="项ç®åç§°">{{ detailData.projectName || "--" }}</el-descriptions-item> |
| | | <el-descriptions-item label="仿¬¾æ¹å¼">{{ detailData.paymentMethod || "--" }}</el-descriptions-item> |
| | | <el-descriptions-item v-if="detailData.ledgerType === '代å¨'" |
| | | label="æ²¹åº">{{ detailData.oilDepotName || "--" }}</el-descriptions-item> |
| | | <el-descriptions-item v-if="detailData.ledgerType === '代å¨'" |
| | | label="å¨ç½å·">{{ detailData.tankNo || "--" }}</el-descriptions-item> |
| | | <el-descriptions-item label="ååéé¢" :span="2"> |
| | | <span style="font-size: 18px; color: #e6a23c; font-weight: bold;"> |
| | | ¥{{ Number(detailData.contractAmount ?? 0).toFixed(2) }} |
| | | </span> |
| | | <span v-if="detailData.exceedsTrustFund" |
| | | class="reject-text" |
| | | style="margin-left: 12px;"> |
| | | å·²è¶
åºè¯¥å®¢æ·ä¿¡æåºé{{ detailData.trustFund != null ? `ï¼ä¿¡æåºéï¼${detailData.trustFund}ï¼` : "" }} |
| | | </span> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | <div v-if="detailData.productData && detailData.productData.length" |
| | | style="margin-top: 20px;"> |
| | | <h4>产åæç»</h4> |
| | | <el-table :data="detailData.productData" |
| | | border |
| | | style="width: 100%"> |
| | | <el-table-column prop="productCategory" label="产å大类" /> |
| | | <el-table-column prop="specificationModel" label="è§æ ¼åå·" /> |
| | | <el-table-column prop="unit" label="åä½" /> |
| | | <el-table-column prop="quantity" label="æ°é" /> |
| | | <el-table-column prop="taxInclusiveUnitPrice" label="å«ç¨åä»·"> |
| | | <template #default="scope">Â¥{{ Number(scope.row.taxInclusiveUnitPrice ?? 0).toFixed(2) }}</template> |
| | | </el-table-column> |
| | | <el-table-column prop="taxInclusiveTotalPrice" label="å«ç¨æ»ä»·"> |
| | | <template #default="scope">Â¥{{ Number(scope.row.taxInclusiveTotalPrice ?? 0).toFixed(2) }}</template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </div> |
| | | <div v-if="attachmentList.length" |
| | | class="detail-block"> |
| | |
| | | const formResolved = computed(() => resolveInstanceFormFields(props.row)); |
| | | |
| | | |
| | | // æ¯å¦ä¸ºç¹æ®å®¡æ¹ç±»åï¼éè´ãåè´§ãæ¥ä»·ï¼ |
| | | // æ¯å¦ä¸ºç¹æ®å®¡æ¹ç±»åï¼éè´ãåè´§ãæ¥ä»·ãéå®å°è´¦ï¼ |
| | | const isSpecialApprovalType = computed(() => { |
| | | return [5, 7, 6].includes(props.row.businessType); |
| | | return [5, 7, 6, 19].includes(props.row.businessType); |
| | | }); |
| | | |
| | | // 详æ
æ°æ®ï¼ç´æ¥ä½¿ç¨ä¼ å
¥ç detail-data åæ°ï¼ |
| | |
| | | :total="page.total" |
| | | @pagination="pagination" |
| | | > |
| | | <template #bizNo="{ row }"> |
| | | <span>{{ businessNoOf(row) || "-" }}</span> |
| | | </template> |
| | | <template #approveType="{ row }"> |
| | | <span class="approve-type-cell" :style="approvalTypeStyle(row.approvalType)"> |
| | | {{ approvalTypeLabel(row.approvalType) }} |
| | |
| | | onBusinessTypePick, |
| | | backToBusinessTypePick, |
| | | approvalTypeLabel, |
| | | businessNoOf, |
| | | approvalActionLabel, |
| | | searchForm, |
| | | tableLoading, |
| | |
| | | import { getQuotationList } from "@/api/salesManagement/salesQuotation.js"; |
| | | import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger.js"; |
| | | import { getDeliveryDetailByShippingNo } from "@/api/salesManagement/deliveryLedger.js"; |
| | | import { ledgerListPage } from "@/api/salesManagement/salesLedger.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | |
| | | return hit?.label || ""; |
| | | } |
| | | |
| | | // å表ãä¸å¡åå·ãï¼æä¸å¡ç±»åå对åºçåå·ï¼19=éå®å°è´¦å®¡æ¹ï¼ |
| | | function businessNoOf(row) { |
| | | return ( |
| | | row?.salesContractNo || |
| | | row?.quotationNo || |
| | | row?.purchaseContractNumber || |
| | | row?.shippingNo || |
| | | row?.bizId || |
| | | "" |
| | | ); |
| | | } |
| | | |
| | | function countTemplatesByBusinessType(type) { |
| | | return allSubmitTemplates.value.filter((card) => matchBusinessTypeValue(card.businessType, type)).length; |
| | | } |
| | |
| | | // { label: "ç³è¯·äººç¼å·", prop: "applicantNo", width: 110 }, |
| | | { label: "å起人", prop: "applicantName", minWidth: 100 }, |
| | | { label: "模æ¿ç±»å", prop: "businessName", minWidth: 120 }, |
| | | { |
| | | label: "ä¸å¡åå·", |
| | | prop: "businessNo", |
| | | minWidth: 170, |
| | | dataType: "slot", |
| | | slot: "bizNo", |
| | | }, |
| | | { |
| | | label: "审æ¹ç±»å", |
| | | prop: "approvalType", |
| | |
| | | } |
| | | } |
| | | |
| | | // éå®å°è´¦å®¡æ¹ï¼ç¨å®¡æ¹äºç±å段æ¿è½½ç"éå®ååå·"廿¥å°è´¦å表 |
| | | else if (row.businessType === 19) { |
| | | detailData.value = await fetchSalesLedgerByContractNo(row?.salesContractNo); |
| | | } |
| | | |
| | | // å
¶ä»å®¡æ¹ç±»å |
| | | else { |
| | | detailData.value = {}; |
| | | } |
| | | |
| | | detailDialog.visible = true; |
| | | } |
| | | |
| | | async function fetchSalesLedgerByContractNo(salesContractNo) { |
| | | if (!salesContractNo) return {}; |
| | | // /sales/ledger/listPage ç´æ¥è¿å IPageï¼é¡¶å± recordsï¼ï¼æ²¡æ code/msg å¤å± |
| | | const res = await ledgerListPage({ |
| | | salesContractNo, |
| | | pageNum: 1, |
| | | pageSize: 1, |
| | | }); |
| | | return res?.records?.[0] || {}; |
| | | } |
| | | |
| | | async function openApprove(row) { |
| | |
| | | const res = await getDeliveryDetailByShippingNo({ shippingNo }); |
| | | detailData.value = res?.data || res || {}; |
| | | } |
| | | } |
| | | |
| | | // éå®å°è´¦å®¡æ¹ï¼ç¨å®¡æ¹äºç±å段æ¿è½½ç"éå®ååå·"廿¥å°è´¦å表 |
| | | else if (row.businessType === 19) { |
| | | detailData.value = await fetchSalesLedgerByContractNo(row?.salesContractNo); |
| | | } |
| | | |
| | | // å
¶ä»å®¡æ¹ç±»å |
| | |
| | | selectedBusinessType, |
| | | selectedBusinessTypeLabel, |
| | | businessTypeLabel, |
| | | businessNoOf, |
| | | countTemplatesByBusinessType, |
| | | submitTemplatesLoading, |
| | | handleQuery, |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <el-form :model="searchForm" |
| | | :inline="true"> |
| | | <el-form-item label="å§å¤è®¢åå·ï¼"> |
| | | <el-input v-model="searchForm.orderNo" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | prefix-icon="Search" |
| | | style="width: 180px" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="åä½åï¼"> |
| | | <el-select v-model="searchForm.partnerId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | | style="width: 200px" |
| | | @change="handleQuery"> |
| | | <el-option v-for="item in partnerOptions" |
| | | :key="item.id" |
| | | :label="item.partnerName" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="项ç®åç§°ï¼"> |
| | | <el-input v-model="searchForm.projectName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | style="width: 160px" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æï¼"> |
| | | <el-select v-model="searchForm.status" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 140px" |
| | | @change="handleQuery"> |
| | | <el-option v-for="item in statusOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ç³è¯·æ¥æï¼"> |
| | | <el-date-picker v-model="dateRange" |
| | | type="daterange" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="handleQuery">æç´¢</el-button> |
| | | <el-button @click="resetSearch">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <div class="table_list"> |
| | | <div class="actions"> |
| | | <div></div> |
| | | <div> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">æ°å¢å§å¤è®¢å</el-button> |
| | | <el-button @click="handleExport">导åº</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleBatchDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <el-table :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | @selection-change="handleSelectionChange" |
| | | style="width: 100%" |
| | | height="calc(100vh - 21.5em)"> |
| | | <el-table-column align="center" |
| | | type="selection" |
| | | :selectable="isDraft" |
| | | width="55" /> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="å§å¤è®¢åå·" |
| | | prop="orderNo" |
| | | min-width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åä½å" |
| | | prop="partnerName" |
| | | min-width="180" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="项ç®åç§°" |
| | | prop="projectName" |
| | | min-width="140" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ç³è¯·æ¥æ" |
| | | prop="applyDate" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="é¢è®¡äº¤ä»æ¥æ" |
| | | prop="expectedDeliveryDate" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ååéé¢(å
)" |
| | | prop="contractAmount" |
| | | min-width="120" |
| | | align="right"> |
| | | <template #default="scope"> |
| | | {{ formatAmount(scope.row.contractAmount) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="仿¬¾æ¹å¼" |
| | | prop="paymentMethod" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ç¶æ" |
| | | prop="status" |
| | | align="center" |
| | | width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="statusTagType(scope.row.status)" |
| | | size="small"> |
| | | {{ statusLabel(scope.row.status) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="确认æ¶é´" |
| | | prop="confirmTime" |
| | | min-width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ä½åºåå " |
| | | prop="cancelReason" |
| | | min-width="140" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å建æ¶é´" |
| | | prop="createTime" |
| | | min-width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column fixed="right" |
| | | label="æä½" |
| | | width="220" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openForm('view', scope.row)">详æ
</el-button> |
| | | <el-button v-if="scope.row.status === 0" |
| | | link |
| | | type="primary" |
| | | @click="openForm('edit', scope.row)">ç¼è¾</el-button> |
| | | <el-button v-if="scope.row.status === 0" |
| | | link |
| | | type="primary" |
| | | @click="handleSubmitOrder(scope.row)">æäº¤</el-button> |
| | | <el-button v-if="scope.row.status === 1" |
| | | link |
| | | type="primary" |
| | | @click="handleCompleteOrder(scope.row)">宿</el-button> |
| | | <el-button v-if="scope.row.status === 0 || scope.row.status === 1" |
| | | link |
| | | type="danger" |
| | | @click="handleCancelOrder(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" /> |
| | | </div> |
| | | <el-dialog v-model="dialogFormVisible" |
| | | :title="dialogTitle" |
| | | width="90%" |
| | | top="5vh" |
| | | :close-on-click-modal="false" |
| | | @close="closeDia"> |
| | | <el-form :model="form" |
| | | label-width="130px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef" |
| | | :disabled="isView"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="8"> |
| | | <el-form-item label="åä½åï¼" |
| | | prop="partnerId"> |
| | | <el-select v-model="form.partnerId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | | style="width: 100%"> |
| | | <el-option v-for="item in partnerOptions" |
| | | :key="item.id" |
| | | :label="item.partnerName" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="项ç®åç§°ï¼" |
| | | prop="projectName"> |
| | | <el-input v-model="form.projectName" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="仿¬¾æ¹å¼ï¼" |
| | | prop="paymentMethod"> |
| | | <el-input v-model="form.paymentMethod" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="8"> |
| | | <el-form-item label="ç³è¯·æ¥æï¼" |
| | | prop="applyDate"> |
| | | <el-date-picker v-model="form.applyDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | placeholder="è¯·éæ©" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="é¢è®¡äº¤ä»æ¥æï¼" |
| | | prop="expectedDeliveryDate"> |
| | | <el-date-picker v-model="form.expectedDeliveryDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | placeholder="è¯·éæ©" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="ååéé¢(å
)"> |
| | | <el-input :model-value="formatAmount(totalAmount)" |
| | | readonly /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨ï¼" |
| | | prop="remarks"> |
| | | <el-input v-model="form.remarks" |
| | | type="textarea" |
| | | :rows="2" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <div class="detail-header"> |
| | | <span class="detail-title">产åæç»</span> |
| | | <el-button v-if="!isView" |
| | | type="primary" |
| | | size="small" |
| | | @click="openScrapSelect">鿥åºå</el-button> |
| | | <el-button v-if="!isView" |
| | | size="small" |
| | | @click="addEmptyDetail">æ°å¢è¡</el-button> |
| | | </div> |
| | | <el-table :data="form.productData" |
| | | border |
| | | size="small" |
| | | style="width: 100%"> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="55" /> |
| | | <el-table-column label="产å大类" |
| | | prop="productCategory" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="specificationModel" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åä½" |
| | | prop="unit" |
| | | min-width="70" /> |
| | | <el-table-column label="æ°é" |
| | | prop="quantity" |
| | | min-width="110"> |
| | | <template #default="scope"> |
| | | <el-input-number v-if="!isView" |
| | | v-model="scope.row.quantity" |
| | | :min="0" |
| | | :precision="4" |
| | | :step="1" |
| | | style="width: 100%" /> |
| | | <span v-else>{{ scope.row.quantity }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç¨ç(%)" |
| | | prop="taxRate" |
| | | min-width="110"> |
| | | <template #default="scope"> |
| | | <el-input-number v-if="!isView" |
| | | v-model="scope.row.taxRate" |
| | | :min="0" |
| | | :max="100" |
| | | :precision="2" |
| | | :step="1" |
| | | style="width: 100%" /> |
| | | <span v-else>{{ scope.row.taxRate }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å«ç¨åä»·(å
)" |
| | | prop="taxInclusiveUnitPrice" |
| | | min-width="130"> |
| | | <template #default="scope"> |
| | | <el-input-number v-if="!isView" |
| | | v-model="scope.row.taxInclusiveUnitPrice" |
| | | :min="0" |
| | | :precision="2" |
| | | :step="0.01" |
| | | style="width: 100%" /> |
| | | <span v-else>{{ scope.row.taxInclusiveUnitPrice }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å«ç¨æ»ä»·(å
)" |
| | | prop="taxInclusiveTotalPrice" |
| | | min-width="120" |
| | | align="right"> |
| | | <template #default="scope"> |
| | | {{ formatAmount(lineTotal(scope.row)) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ¥åºå" |
| | | prop="isScrap" |
| | | align="center" |
| | | width="80"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.isScrap ? 'warning' : 'info'" |
| | | size="small"> |
| | | {{ scope.row.isScrap ? "æ¯" : "å¦" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ¹å·" |
| | | prop="batchNo" |
| | | min-width="130" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å¯ç¨é" |
| | | prop="availableQuantity" |
| | | min-width="100" |
| | | align="right" /> |
| | | <el-table-column label="夿³¨" |
| | | prop="remark" |
| | | min-width="130"> |
| | | <template #default="scope"> |
| | | <el-input v-if="!isView" |
| | | v-model="scope.row.remark" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | <span v-else>{{ scope.row.remark }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column v-if="!isView" |
| | | fixed="right" |
| | | label="æä½" |
| | | width="70" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-button link |
| | | type="danger" |
| | | @click="removeDetail(scope.$index)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button v-if="!isView" |
| | | type="primary" |
| | | @click="submitForm">确认</el-button> |
| | | <el-button @click="closeDia">{{ isView ? "å
³é" : "åæ¶" }}</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- æ¥åºåéæï¼åªè¯»ï¼ä¸æ£åºåãä¸å ç¨ï¼ --> |
| | | <el-dialog v-model="scrapDialogVisible" |
| | | title="éæ©æ¥åºå" |
| | | width="70%" |
| | | append-to-body> |
| | | <el-form :model="scrapSearch" |
| | | :inline="true"> |
| | | <el-form-item label="产ååç§°ï¼"> |
| | | <el-input v-model="scrapSearch.productName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | style="width: 160px" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¹å·ï¼"> |
| | | <el-input v-model="scrapSearch.batchNo" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | style="width: 160px" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="handleScrapQuery">æç´¢</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <el-table :data="scrapTableData" |
| | | border |
| | | v-loading="scrapLoading" |
| | | highlight-current-row |
| | | style="width: 100%" |
| | | height="360px" |
| | | @current-change="handleScrapCurrentChange"> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="产ååç§°" |
| | | prop="productName" |
| | | min-width="140" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="model" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ¹å·" |
| | | prop="batchNo" |
| | | min-width="140" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åä½" |
| | | prop="unit" |
| | | min-width="70" /> |
| | | <el-table-column label="åºåæ°é" |
| | | prop="qualitity" |
| | | min-width="100" |
| | | align="right" /> |
| | | <el-table-column label="é宿°é" |
| | | prop="lockedQuantity" |
| | | min-width="100" |
| | | align="right" /> |
| | | <el-table-column label="å¯ç¨æ°é" |
| | | prop="unLockedQuantity" |
| | | min-width="100" |
| | | align="right" /> |
| | | <el-table-column label="夿³¨" |
| | | prop="remark" |
| | | min-width="120" |
| | | show-overflow-tooltip /> |
| | | </el-table> |
| | | <pagination v-show="scrapTotal > 0" |
| | | :total="scrapTotal" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :page="scrapPage.current" |
| | | :limit="scrapPage.size" |
| | | @pagination="scrapPaginationChange" /> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" |
| | | @click="confirmScrapSelect">确认</el-button> |
| | | <el-button @click="scrapDialogVisible = false">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, computed, toRefs, getCurrentInstance, onMounted } from "vue"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { |
| | | listOutsourcingOrder, |
| | | getOutsourcingOrder, |
| | | addOutsourcingOrder, |
| | | editOutsourcingOrder, |
| | | delOutsourcingOrder, |
| | | submitOutsourcingOrder, |
| | | completeOutsourcingOrder, |
| | | cancelOutsourcingOrder, |
| | | exportOutsourcingOrder, |
| | | scrapStockPage, |
| | | } from "@/api/outsourcing/order.js"; |
| | | import { getPartnerOptions } from "@/api/outsourcing/partner.js"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | const dialogFormVisible = ref(false); |
| | | const operationType = ref(""); |
| | | const partnerOptions = ref([]); |
| | | const dateRange = ref([]); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | }); |
| | | const total = ref(0); |
| | | |
| | | const statusOptions = [ |
| | | { label: "è稿", value: 0 }, |
| | | { label: "已确认", value: 1 }, |
| | | { label: "已宿", value: 2 }, |
| | | { label: "å·²ä½åº", value: 3 }, |
| | | ]; |
| | | |
| | | const statusLabelMap = { |
| | | 0: "è稿", |
| | | 1: "已确认", |
| | | 2: "已宿", |
| | | 3: "å·²ä½åº", |
| | | }; |
| | | |
| | | const statusTagMap = { |
| | | 0: "info", |
| | | 1: "primary", |
| | | 2: "success", |
| | | 3: "danger", |
| | | }; |
| | | |
| | | const statusLabel = status => statusLabelMap[status] ?? status; |
| | | const statusTagType = status => statusTagMap[status] || "info"; |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | orderNo: "", |
| | | partnerId: "", |
| | | projectName: "", |
| | | status: "", |
| | | }, |
| | | form: {}, |
| | | rules: { |
| | | partnerId: [{ required: true, message: "è¯·éæ©åä½å", trigger: "change" }], |
| | | projectName: [{ required: true, message: "请è¾å
¥é¡¹ç®åç§°", trigger: "blur" }], |
| | | applyDate: [{ required: true, message: "è¯·éæ©ç³è¯·æ¥æ", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { searchForm, form, rules } = toRefs(data); |
| | | |
| | | const isView = computed(() => operationType.value === "view"); |
| | | const isDraft = row => row.status === 0; |
| | | const dialogTitle = computed(() => { |
| | | if (operationType.value === "add") { |
| | | return "æ°å¢å§å¤è®¢å"; |
| | | } |
| | | return operationType.value === "edit" ? "ç¼è¾å§å¤è®¢å" : "å§å¤è®¢å详æ
"; |
| | | }); |
| | | |
| | | const buildEmptyForm = () => ({ |
| | | id: null, |
| | | partnerId: undefined, |
| | | projectName: "", |
| | | applyDate: today(), |
| | | expectedDeliveryDate: "", |
| | | paymentMethod: "", |
| | | remarks: "", |
| | | productData: [], |
| | | }); |
| | | |
| | | function today() { |
| | | const d = new Date(); |
| | | const month = String(d.getMonth() + 1).padStart(2, "0"); |
| | | const day = String(d.getDate()).padStart(2, "0"); |
| | | return `${d.getFullYear()}-${month}-${day}`; |
| | | } |
| | | |
| | | const formatAmount = value => { |
| | | const num = Number(value); |
| | | return Number.isFinite(num) ? num.toFixed(2) : "0.00"; |
| | | }; |
| | | |
| | | // å«ç¨æ»ä»·ç±æ°é à å«ç¨åä»·å¾åºï¼åç«¯ä¼ææç»å计è¦ç contractAmount |
| | | const lineTotal = row => { |
| | | const quantity = Number(row?.quantity) || 0; |
| | | const price = Number(row?.taxInclusiveUnitPrice) || 0; |
| | | return Math.round(quantity * price * 100) / 100; |
| | | }; |
| | | |
| | | const totalAmount = computed(() => |
| | | (form.value.productData || []).reduce((sum, row) => sum + lineTotal(row), 0) |
| | | ); |
| | | |
| | | // å»æç©ºå¼ï¼é¿å
status='' è¿ç±»ç©ºä¸²è¢«åç«¯å½æ 0ï¼è稿ï¼è§£æ |
| | | const compact = obj => |
| | | Object.fromEntries( |
| | | Object.entries(obj).filter(([, v]) => v !== "" && v !== null && v !== undefined) |
| | | ); |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | const [startDate, endDate] = dateRange.value || []; |
| | | listOutsourcingOrder({ |
| | | pageNum: page.current, |
| | | pageSize: page.size, |
| | | ...compact(searchForm.value), |
| | | startDate, |
| | | endDate, |
| | | }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | // å§å¤è®¢åå表è¿åçæ¯ RuoYi ç»æï¼è¡å¨é¡¶å± rows |
| | | tableData.value = res.rows || []; |
| | | total.value = res.total || 0; |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const resetSearch = () => { |
| | | searchForm.value = { orderNo: "", partnerId: "", projectName: "", status: "" }; |
| | | dateRange.value = []; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | const paginationChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | |
| | | const openForm = (type, row) => { |
| | | operationType.value = type; |
| | | form.value = buildEmptyForm(); |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = true; |
| | | if (type !== "add" && row) { |
| | | getOutsourcingOrder(row.id).then(res => { |
| | | const detail = res.data || {}; |
| | | form.value = { |
| | | ...buildEmptyForm(), |
| | | ...detail, |
| | | productData: (detail.productData || []).map(item => ({ ...item })), |
| | | }; |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | const addEmptyDetail = () => { |
| | | form.value.productData.push({ |
| | | productId: undefined, |
| | | productModelId: undefined, |
| | | productCategory: "", |
| | | specificationModel: "", |
| | | unit: "", |
| | | quantity: undefined, |
| | | taxRate: undefined, |
| | | taxInclusiveUnitPrice: undefined, |
| | | taxInclusiveTotalPrice: undefined, |
| | | isScrap: false, |
| | | stockInventoryId: undefined, |
| | | batchNo: "", |
| | | availableQuantity: undefined, |
| | | remark: "", |
| | | }); |
| | | }; |
| | | |
| | | const removeDetail = index => { |
| | | form.value.productData.splice(index, 1); |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | if (!form.value.productData.length) { |
| | | proxy.$modal.msgWarning("请è³å°æ·»å 䏿¡äº§åæç»"); |
| | | return; |
| | | } |
| | | // åªæäº¤ææ¡£çº¦å®çåæ®µï¼åå·/ç¶æ/确认æ¶é´/ååéé¢/åä½ååç§°çç±åç«¯ç»´æ¤ |
| | | const payload = { |
| | | partnerId: form.value.partnerId, |
| | | projectName: form.value.projectName, |
| | | applyDate: form.value.applyDate, |
| | | expectedDeliveryDate: form.value.expectedDeliveryDate, |
| | | paymentMethod: form.value.paymentMethod, |
| | | remarks: form.value.remarks, |
| | | productData: form.value.productData.map(row => ({ |
| | | productId: row.productId, |
| | | productModelId: row.productModelId, |
| | | productCategory: row.productCategory, |
| | | specificationModel: row.specificationModel, |
| | | unit: row.unit, |
| | | quantity: row.quantity, |
| | | taxRate: row.taxRate, |
| | | taxInclusiveUnitPrice: row.taxInclusiveUnitPrice, |
| | | taxInclusiveTotalPrice: lineTotal(row), |
| | | isScrap: !!row.isScrap, |
| | | stockInventoryId: row.stockInventoryId, |
| | | batchNo: row.batchNo, |
| | | availableQuantity: row.availableQuantity, |
| | | remark: row.remark, |
| | | })), |
| | | ...(form.value.id ? { id: form.value.id } : {}), |
| | | }; |
| | | const api = form.value.id ? editOutsourcingOrder : addOutsourcingOrder; |
| | | api(payload).then(() => { |
| | | proxy.$modal.msgSuccess("æä½æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | |
| | | const handleSubmitOrder = row => { |
| | | ElMessageBox.confirm( |
| | | `æ¯å¦ç¡®è®¤æäº¤è®¢å ${row.orderNo}ï¼æäº¤åå°å ç¨æéæ¥åºåæ¹æ¬¡çå¯ç¨éï¼éå°åºåºç®¡ç审æ¹éè¿åæè½å®æè®¢åã`, |
| | | "æäº¤", |
| | | { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | } |
| | | ) |
| | | .then(() => { |
| | | submitOutsourcingOrder(row.id).then(() => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | const handleCompleteOrder = row => { |
| | | ElMessageBox.confirm(`æ¯å¦ç¡®è®¤å®æè®¢å ${row.orderNo}ï¼`, "宿", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | completeOutsourcingOrder(row.id).then(() => { |
| | | proxy.$modal.msgSuccess("æä½æå"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | const handleCancelOrder = row => { |
| | | ElMessageBox.prompt("请è¾å
¥ä½åºåå ï¼å¯ä¸å¡«ï¼", `ä½åºè®¢å ${row.orderNo}`, { |
| | | confirmButtonText: "确认ä½åº", |
| | | cancelButtonText: "åæ¶", |
| | | inputPlaceholder: "ä½åºåå ", |
| | | }) |
| | | .then(({ value }) => { |
| | | cancelOutsourcingOrder(row.id, value || "").then(() => { |
| | | proxy.$modal.msgSuccess("ä½åºæå"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | const handleBatchDelete = () => { |
| | | if (selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼ä»
èç¨¿ç¶æå
许å é¤ã", "å é¤", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | delOutsourcingOrder(ids).then(() => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | const saveExcelBlob = (blobData, filename) => { |
| | | const blob = new Blob([blobData], { |
| | | type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", |
| | | }); |
| | | const url = window.URL.createObjectURL(blob); |
| | | const link = document.createElement("a"); |
| | | link.href = url; |
| | | link.download = filename; |
| | | document.body.appendChild(link); |
| | | link.click(); |
| | | setTimeout(() => { |
| | | document.body.removeChild(link); |
| | | window.URL.revokeObjectURL(url); |
| | | }, 100); |
| | | }; |
| | | |
| | | const handleExport = () => { |
| | | ElMessageBox.confirm("æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | const [startDate, endDate] = dateRange.value || []; |
| | | exportOutsourcingOrder({ |
| | | ...compact(searchForm.value), |
| | | startDate, |
| | | endDate, |
| | | }).then(res => { |
| | | saveExcelBlob(res, "å§å¤è®¢å.xlsx"); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | // æ¥åºåéæï¼åªè¯»å¸¦åºï¼ä¸æ£åºåãä¸å ç¨ |
| | | const scrapDialogVisible = ref(false); |
| | | const scrapLoading = ref(false); |
| | | const scrapTableData = ref([]); |
| | | const scrapSelectedRow = ref(null); |
| | | const scrapTotal = ref(0); |
| | | const scrapPage = reactive({ current: 1, size: 10 }); |
| | | const scrapSearch = reactive({ productName: "", batchNo: "" }); |
| | | |
| | | const getScrapList = () => { |
| | | scrapLoading.value = true; |
| | | scrapStockPage({ |
| | | pageNum: scrapPage.current, |
| | | pageSize: scrapPage.size, |
| | | productName: scrapSearch.productName || undefined, |
| | | batchNo: scrapSearch.batchNo || undefined, |
| | | }) |
| | | .then(res => { |
| | | scrapLoading.value = false; |
| | | scrapTableData.value = res.data?.records || []; |
| | | scrapTotal.value = res.data?.total || 0; |
| | | }) |
| | | .catch(() => { |
| | | scrapLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const openScrapSelect = () => { |
| | | scrapSelectedRow.value = null; |
| | | scrapSearch.productName = ""; |
| | | scrapSearch.batchNo = ""; |
| | | scrapPage.current = 1; |
| | | scrapDialogVisible.value = true; |
| | | getScrapList(); |
| | | }; |
| | | |
| | | const handleScrapQuery = () => { |
| | | scrapPage.current = 1; |
| | | getScrapList(); |
| | | }; |
| | | |
| | | const scrapPaginationChange = obj => { |
| | | scrapPage.current = obj.page; |
| | | scrapPage.size = obj.limit; |
| | | getScrapList(); |
| | | }; |
| | | |
| | | const handleScrapCurrentChange = row => { |
| | | scrapSelectedRow.value = row; |
| | | }; |
| | | |
| | | const confirmScrapSelect = () => { |
| | | const row = scrapSelectedRow.value; |
| | | if (!row) { |
| | | proxy.$modal.msgWarning("è¯·éæ©ä¸æ¡æ¥åºåæ¹æ¬¡"); |
| | | return; |
| | | } |
| | | form.value.productData.push({ |
| | | productId: row.productId, |
| | | productModelId: row.productModelId, |
| | | productCategory: row.productName || "", |
| | | specificationModel: row.model || "", |
| | | unit: row.unit || "", |
| | | quantity: undefined, |
| | | taxRate: undefined, |
| | | taxInclusiveUnitPrice: undefined, |
| | | taxInclusiveTotalPrice: undefined, |
| | | isScrap: true, |
| | | stockInventoryId: row.id, |
| | | batchNo: row.batchNo || "", |
| | | availableQuantity: row.unLockedQuantity, |
| | | remark: "", |
| | | }); |
| | | scrapDialogVisible.value = false; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | getPartnerOptions().then(res => { |
| | | partnerOptions.value = res.data || []; |
| | | }); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .search_form { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .actions { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .detail-header { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | margin: 8px 0 12px; |
| | | |
| | | .detail-title { |
| | | flex: 1; |
| | | font-size: 15px; |
| | | font-weight: 600; |
| | | color: #1d6fd8; |
| | | } |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <el-form :model="searchForm" |
| | | :inline="true"> |
| | | <el-form-item label="åä½ååç§°ï¼"> |
| | | <el-input v-model="searchForm.partnerName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="åä½åç±»åï¼"> |
| | | <el-input v-model="searchForm.partnerType" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¯å¦ç½ååï¼"> |
| | | <el-select v-model="searchForm.isWhite" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 140px" |
| | | @change="handleQuery"> |
| | | <el-option label="æ¯" |
| | | :value="1" /> |
| | | <el-option label="å¦" |
| | | :value="0" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="handleQuery">æç´¢</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <div class="table_list"> |
| | | <div class="actions"> |
| | | <div></div> |
| | | <div> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">æ°å¢åä½å</el-button> |
| | | <el-button @click="handleExport">导åº</el-button> |
| | | <el-button type="info" |
| | | plain |
| | | icon="Upload" |
| | | @click="handleImport">导å
¥</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <el-table :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | @selection-change="handleSelectionChange" |
| | | style="width: 100%" |
| | | height="calc(100vh - 19em)"> |
| | | <el-table-column align="center" |
| | | type="selection" |
| | | width="55" /> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="åä½ååç§°" |
| | | prop="partnerName" |
| | | min-width="200" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åä½åç±»å" |
| | | prop="partnerType" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="纳ç¨äººè¯å«å·" |
| | | prop="taxpayerIdentificationNum" |
| | | min-width="190" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å
¬å¸å°å" |
| | | prop="companyAddress" |
| | | min-width="180" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å
¬å¸çµè¯" |
| | | prop="companyPhone" |
| | | min-width="130" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="弿·è¡" |
| | | prop="bankAccountName" |
| | | min-width="170" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="è´¦å·" |
| | | prop="bankAccountNum" |
| | | min-width="170" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="è系人" |
| | | prop="contactUserName" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="èç³»çµè¯" |
| | | prop="contactUserPhone" |
| | | min-width="130" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ¯å¦ç½åå" |
| | | prop="isWhite" |
| | | align="center" |
| | | width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.isWhite === 1 ? 'success' : 'info'" |
| | | size="small"> |
| | | {{ scope.row.isWhite === 1 ? "æ¯" : "å¦" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç»´æ¤äºº" |
| | | prop="maintainUserName" |
| | | min-width="90" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ç»´æ¤æ¶é´" |
| | | prop="maintainTime" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="夿³¨" |
| | | prop="remark" |
| | | min-width="140" |
| | | show-overflow-tooltip /> |
| | | <el-table-column fixed="right" |
| | | label="æä½" |
| | | width="160" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openForm('edit', scope.row)">ç¼è¾</el-button> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openAttachment(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" /> |
| | | </div> |
| | | <el-dialog v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢åä½å' : 'ç¼è¾åä½å'" |
| | | width="70%" |
| | | :close-on-click-modal="false" |
| | | @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="partnerName"> |
| | | <el-input v-model="form.partnerName" |
| | | 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="partnerType"> |
| | | <el-input v-model="form.partnerType" |
| | | placeholder="请è¾å
¥ï¼å¦ï¼å±åºå¤ç½®" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¯å¦ç½ååï¼" |
| | | prop="isWhite"> |
| | | <el-select v-model="form.isWhite" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 100%"> |
| | | <el-option label="æ¯" |
| | | :value="1" /> |
| | | <el-option label="å¦" |
| | | :value="0" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨ï¼" |
| | | prop="remark"> |
| | | <el-input v-model="form.remark" |
| | | type="textarea" |
| | | :rows="2" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="éä»¶ï¼"> |
| | | <AttachmentUploadFile v-model:file-list="partnerFileList" |
| | | :limit="10" /> |
| | | </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" |
| | | :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>ä»
å
许导å
¥xlsãxlsxæ ¼å¼æä»¶ã</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-dialog v-model="attachmentVisible" |
| | | title="éä»¶" |
| | | width="600px" |
| | | append-to-body> |
| | | <div v-loading="attachmentLoading" |
| | | style="min-height: 140px"> |
| | | <AttachmentUploadFile v-model:file-list="attachmentList" |
| | | :limit="10" |
| | | @change="saveAttachments" /> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, toRefs, getCurrentInstance, onMounted } from "vue"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import AttachmentUploadFile from "@/components/AttachmentUpload/file/index.vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | import { |
| | | listPartner, |
| | | getPartner, |
| | | addPartner, |
| | | updatePartner, |
| | | delPartner, |
| | | exportPartner, |
| | | downloadPartnerTemplate, |
| | | } from "@/api/outsourcing/partner.js"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | const dialogFormVisible = ref(false); |
| | | const attachmentVisible = ref(false); |
| | | const attachmentList = ref([]); |
| | | const attachmentLoading = ref(false); |
| | | // éä»¶å¼¹æ¡å¯¹åºçåä½å详æ
ï¼å表è¡å段ä¸å
¨ï¼ä¿åæ¶ç¨è¯¦æ
éçåæ®µæ´ä½åä¼ |
| | | const attachmentDetail = ref({}); |
| | | const operationType = ref(""); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | }); |
| | | const total = ref(0); |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | partnerName: "", |
| | | partnerType: "", |
| | | isWhite: "", |
| | | }, |
| | | form: {}, |
| | | rules: { |
| | | partnerName: [{ required: true, message: "请è¾å
¥åä½ååç§°", trigger: "blur" }], |
| | | }, |
| | | }); |
| | | const { searchForm, form, rules } = toRefs(data); |
| | | // éä»¶é表åä¸å¹¶æäº¤ï¼å端æ storageBlobDTOS å
¨éè¦çï¼æ¸
空å³è§£ç» |
| | | const partnerFileList = ref([]); |
| | | |
| | | // åä½åç±»åçåæ®µå端æªç»åå
¸ï¼ç±»åæèªç±ææ¬ç»´æ¤ |
| | | const buildEmptyForm = () => ({ |
| | | id: null, |
| | | partnerName: "", |
| | | taxpayerIdentificationNum: "", |
| | | companyAddress: "", |
| | | companyPhone: "", |
| | | bankAccountName: "", |
| | | bankAccountNum: "", |
| | | contactUserName: "", |
| | | contactUserPhone: "", |
| | | partnerType: "", |
| | | isWhite: 0, |
| | | remark: "", |
| | | }); |
| | | |
| | | // å»æç©ºå¼ï¼é¿å
isWhite='' è¿ç±»ç©ºä¸²è¢«åç«¯å½æ 0 è§£æ |
| | | const compact = obj => |
| | | Object.fromEntries( |
| | | Object.entries(obj).filter(([, v]) => v !== "" && v !== null && v !== undefined) |
| | | ); |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | listPartner({ |
| | | pageNum: page.current, |
| | | pageSize: page.size, |
| | | ...compact(searchForm.value), |
| | | }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data?.records || []; |
| | | total.value = res.data?.total || 0; |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const paginationChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | |
| | | const openForm = (type, row) => { |
| | | operationType.value = type; |
| | | form.value = buildEmptyForm(); |
| | | partnerFileList.value = []; |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = true; |
| | | if (type === "edit" && row) { |
| | | // 详æ
è¿åçéä»¶å¯è½æ¯ storageBlobVOS æ storageBlobDTOSï¼åæ¾åç»ä¸è½¬æ storageBlobDTOS å
¨éæäº¤ |
| | | getPartner(row.id).then(res => { |
| | | const { storageBlobVOS, storageBlobDTOS, ...detail } = res.data || {}; |
| | | form.value = { ...buildEmptyForm(), ...detail }; |
| | | partnerFileList.value = storageBlobVOS || storageBlobDTOS || []; |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | // åªæäº¤ææ¡£çº¦å®çåæ®µï¼ç»´æ¤äºº/ç»´æ¤æ¶é´/å建æ¶é´çç±åç«¯ç»´æ¤ |
| | | // source/files å¯ä¼ åï¼éä»¶å¼¹æ¡ä¿åæ¶ç¨çæ¯è¯¦æ
æ°æ® + å¼¹æ¡å
çéä»¶å表 |
| | | const buildPayload = (source = form.value, files = partnerFileList.value) => { |
| | | const { |
| | | id, |
| | | partnerName, |
| | | taxpayerIdentificationNum, |
| | | companyAddress, |
| | | companyPhone, |
| | | bankAccountName, |
| | | bankAccountNum, |
| | | contactUserName, |
| | | contactUserPhone, |
| | | partnerType, |
| | | isWhite, |
| | | remark, |
| | | } = source || {}; |
| | | return { |
| | | partnerName, |
| | | taxpayerIdentificationNum, |
| | | companyAddress, |
| | | companyPhone, |
| | | bankAccountName, |
| | | bankAccountNum, |
| | | contactUserName, |
| | | contactUserPhone, |
| | | partnerType, |
| | | isWhite, |
| | | remark, |
| | | storageBlobDTOS: (files || []) |
| | | .filter(item => item && item.id != null) |
| | | .map(item => ({ id: item.id })), |
| | | ...(id ? { id } : {}), |
| | | }; |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | const api = form.value.id ? updatePartner : addPartner; |
| | | api(buildPayload()).then(() => { |
| | | proxy.$modal.msgSuccess("æä½æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | partnerFileList.value = []; |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | |
| | | // å
å¼¹æ¡åæéä»¶ï¼è¯¦æ
æ¥å£æ
¢æå¤±è´¥æ¶ï¼æé®ä¹ä¸ä¼çèµ·æ¥å没ååº |
| | | const openAttachment = row => { |
| | | attachmentList.value = []; |
| | | attachmentDetail.value = {}; |
| | | attachmentVisible.value = true; |
| | | attachmentLoading.value = true; |
| | | getPartner(row.id) |
| | | .then(res => { |
| | | attachmentDetail.value = res.data || {}; |
| | | // åä½å详æ
å端æéä»¶æ¾å¨ storageBlobDTOSï¼å
¶å®æ¨¡åç VO æå« storageBlobVOSï¼ï¼ä¸¤ä¸ªé½å
ä½ |
| | | attachmentList.value = res.data?.storageBlobVOS || res.data?.storageBlobDTOS || []; |
| | | }) |
| | | .catch(() => { |
| | | attachmentList.value = []; |
| | | }) |
| | | .finally(() => { |
| | | attachmentLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | // å¼¹æ¡å
ä¸ä¼ /å é¤åç«å³ä¿åï¼å端æ storageBlobDTOS å
¨éè¦çï¼æä»¥æ´ä»½å表åä¼ |
| | | const saveAttachments = files => { |
| | | const list = Array.isArray(files) ? files : attachmentList.value; |
| | | attachmentList.value = list; |
| | | if (!attachmentDetail.value?.id) { |
| | | proxy.$modal.msgError("æªè·åå°åä½åä¿¡æ¯ï¼éä»¶ä¿å失败"); |
| | | return; |
| | | } |
| | | attachmentLoading.value = true; |
| | | updatePartner(buildPayload(attachmentDetail.value, list)) |
| | | .then(() => { |
| | | attachmentDetail.value = { |
| | | ...attachmentDetail.value, |
| | | storageBlobDTOS: list, |
| | | }; |
| | | proxy.$modal.msgSuccess("éä»¶å·²ä¿å"); |
| | | }) |
| | | .finally(() => { |
| | | attachmentLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const handleDelete = () => { |
| | | if (selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | ElMessageBox.confirm( |
| | | "éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼å·²åå¨å§å¤è®¢åæå¾æ¥æ¶ä»æ¬¾è®°å½çåä½åä¸å
许å é¤ã", |
| | | "å é¤", |
| | | { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | } |
| | | ) |
| | | .then(() => { |
| | | delPartner(ids).then(() => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | // ä¿å Excel æä»¶æµ |
| | | const saveExcelBlob = (data, filename) => { |
| | | const blob = new Blob([data], { |
| | | type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", |
| | | }); |
| | | const url = window.URL.createObjectURL(blob); |
| | | const link = document.createElement("a"); |
| | | link.href = url; |
| | | link.download = filename; |
| | | document.body.appendChild(link); |
| | | link.click(); |
| | | setTimeout(() => { |
| | | document.body.removeChild(link); |
| | | window.URL.revokeObjectURL(url); |
| | | }, 100); |
| | | }; |
| | | |
| | | const handleExport = () => { |
| | | ElMessageBox.confirm("æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | exportPartner(compact(searchForm.value)).then(res => { |
| | | saveExcelBlob(res, "åä½åæ¡£æ¡.xlsx"); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | const upload = reactive({ |
| | | open: false, |
| | | title: "", |
| | | isUploading: false, |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | url: import.meta.env.VITE_APP_BASE_API + "/outsourcing/partner/import", |
| | | }); |
| | | |
| | | const handleImport = () => { |
| | | upload.title = "åä½å导å
¥"; |
| | | upload.open = true; |
| | | }; |
| | | |
| | | const importTemplate = () => { |
| | | downloadPartnerTemplate().then(res => { |
| | | saveExcelBlob(res, "åä½å导å
¥æ¨¡æ¿.xlsx"); |
| | | }); |
| | | }; |
| | | |
| | | const handleFileUploadProgress = () => { |
| | | upload.isUploading = true; |
| | | }; |
| | | |
| | | const handleFileSuccess = response => { |
| | | upload.isUploading = false; |
| | | if (response.code === 200) { |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); |
| | | upload.open = false; |
| | | proxy.$refs["uploadRef"].clearFiles(); |
| | | getList(); |
| | | } else { |
| | | proxy.$modal.msgError(response.msg); |
| | | } |
| | | }; |
| | | |
| | | const handleFileError = () => { |
| | | upload.isUploading = false; |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | }; |
| | | |
| | | const submitFileForm = () => { |
| | | upload.isUploading = true; |
| | | proxy.$refs["uploadRef"].submit(); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .search_form { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .actions { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-bottom: 12px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form" |
| | | style="margin-bottom: 20px;"> |
| | | <span class="search_title">åä½ååç§°ï¼</span> |
| | | <el-input v-model="searchForm.partnerName" |
| | | style="width: 240px" |
| | | placeholder="è¾å
¥åä½ååç§°" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" /> |
| | | <el-button type="primary" |
| | | @click="handleQuery" |
| | | style="margin-left: 10px">æç´¢</el-button> |
| | | </div> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="14"> |
| | | <div class="table_list"> |
| | | <el-table border |
| | | v-loading="tableLoading" |
| | | :data="tableData" |
| | | highlight-current-row |
| | | style="width: 100%" |
| | | height="calc(100vh - 18.5em)" |
| | | @row-click="rowClick"> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="åä½ååç§°" |
| | | prop="partnerName" |
| | | min-width="180" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ååéé¢(å
)" |
| | | prop="contractAmounts" |
| | | min-width="130"> |
| | | <template #default="scope"> |
| | | {{ formatAmount(scope.row.contractAmounts) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="仿¬¾éé¢(å
)" |
| | | prop="paidAmount" |
| | | min-width="130"> |
| | | <template #default="scope"> |
| | | {{ formatAmount(scope.row.paidAmount) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åºä»éé¢(å
)" |
| | | prop="payableAmount" |
| | | min-width="130"> |
| | | <template #default="scope"> |
| | | <el-text type="danger">{{ formatAmount(scope.row.payableAmount) }}</el-text> |
| | | </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> |
| | | </el-col> |
| | | <el-col :span="10"> |
| | | <div class="table_list"> |
| | | <div class="detail-tip"> |
| | | åºä»ä½é¢ = 已确认/已宿çå§å¤è®¢åéé¢ â 已仿¬¾ï¼æç»æ¯è¡çã已仿¬¾ã为åä½å级å计ï¼é订å级ã |
| | | </div> |
| | | <el-table border |
| | | v-loading="detailLoading" |
| | | :data="detailTableData" |
| | | style="width: 100%" |
| | | height="calc(100vh - 21em)"> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="å§å¤è®¢åå·" |
| | | prop="orderNo" |
| | | min-width="150" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ç³è¯·æ¥æ" |
| | | prop="applyDate" |
| | | min-width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="订åéé¢(å
)" |
| | | prop="contractAmount" |
| | | min-width="120"> |
| | | <template #default="scope"> |
| | | {{ formatAmount(scope.row.contractAmount) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç¶æ" |
| | | prop="status" |
| | | align="center" |
| | | width="90"> |
| | | <template #default="scope"> |
| | | <el-tag :type="statusTagType(scope.row.status)" |
| | | size="small"> |
| | | {{ statusLabel(scope.row.status) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åä½å已仿¬¾(å
)" |
| | | prop="paidAmount" |
| | | min-width="140"> |
| | | <template #default="scope"> |
| | | {{ formatAmount(scope.row.paidAmount) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åºä»éé¢(å
)" |
| | | prop="payableAmount" |
| | | min-width="120"> |
| | | <template #default="scope"> |
| | | <el-text type="danger">{{ formatAmount(scope.row.payableAmount) }}</el-text> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" |
| | | label="æä½" |
| | | width="110" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-button link |
| | | type="primary" |
| | | @click.stop="openPaymentDialog(scope.row)">æ°å¢ä»æ¬¾</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | <PaymentRecordDialog v-model:visible="paymentDialogVisible" |
| | | title="åä½å仿¬¾æµæ°´" |
| | | :party-type="3" |
| | | :party-id="paymentPartyId" |
| | | :party-name="paymentPartyName" |
| | | :direction="1" |
| | | @changed="refreshAll" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, toRefs } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import PaymentRecordDialog from "@/components/PaymentRecordDialog/index.vue"; |
| | | import { |
| | | partnerTransactions, |
| | | partnerTransactionsDetails, |
| | | } from "@/api/outsourcing/report.js"; |
| | | |
| | | const tableData = ref([]); |
| | | const detailTableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const detailLoading = ref(false); |
| | | const total = ref(0); |
| | | const page = reactive({ current: 1, size: 10 }); |
| | | const currentPartnerId = ref(""); |
| | | |
| | | const paymentDialogVisible = ref(false); |
| | | const paymentPartyId = ref(""); |
| | | const paymentPartyName = ref(""); |
| | | |
| | | const statusLabelMap = { 0: "è稿", 1: "已确认", 2: "已宿", 3: "å·²ä½åº" }; |
| | | const statusTagMap = { 0: "info", 1: "primary", 2: "success", 3: "danger" }; |
| | | const statusLabel = status => statusLabelMap[status] ?? status; |
| | | const statusTagType = status => statusTagMap[status] || "info"; |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | partnerName: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | const formatAmount = value => { |
| | | const num = Number(value); |
| | | return Number.isFinite(num) ? num.toFixed(2) : "0.00"; |
| | | }; |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | partnerTransactions({ |
| | | pageNum: page.current, |
| | | pageSize: page.size, |
| | | ...searchForm.value, |
| | | }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data?.records || []; |
| | | total.value = res.data?.total || 0; |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const getDetailList = partnerId => { |
| | | if (!partnerId) { |
| | | detailTableData.value = []; |
| | | return; |
| | | } |
| | | detailLoading.value = true; |
| | | partnerTransactionsDetails(partnerId) |
| | | .then(res => { |
| | | detailLoading.value = false; |
| | | detailTableData.value = res.data?.records || []; |
| | | }) |
| | | .catch(() => { |
| | | detailLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const paginationChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | const rowClick = row => { |
| | | currentPartnerId.value = row.partnerId; |
| | | getDetailList(row.partnerId); |
| | | }; |
| | | |
| | | const openPaymentDialog = row => { |
| | | paymentPartyId.value = row.partnerId; |
| | | paymentPartyName.value = row.partnerName || ""; |
| | | paymentDialogVisible.value = true; |
| | | }; |
| | | |
| | | const refreshAll = () => { |
| | | getList(); |
| | | getDetailList(currentPartnerId.value); |
| | | }; |
| | | |
| | | getList(); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .detail-tip { |
| | | margin-bottom: 10px; |
| | | padding: 8px 12px; |
| | | font-size: 12px; |
| | | line-height: 1.6; |
| | | color: #909399; |
| | | background: rgba(64, 158, 255, 0.08); |
| | | border-left: 3px solid #409eff; |
| | | border-radius: 3px; |
| | | } |
| | | </style> |
| | |
| | | prop="paymentAmount" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="éè´§éé¢(å
)" |
| | | prop="returnAmount" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" /> |
| | | <!-- <el-table-column label="忬¾éé¢(å
)"--> |
| | | <!-- prop="receiptAmount"--> |
| | | <!-- show-overflow-tooltip--> |
| | | <!-- :formatter="formattedNumber" />--> |
| | | <!-- <el-table-column label="éè´§éé¢(å
)"--> |
| | | <!-- prop="returnAmount"--> |
| | | <!-- show-overflow-tooltip--> |
| | | <!-- :formatter="formattedNumber" />--> |
| | | <el-table-column label="åºä»éé¢(å
)" |
| | | prop="payableAmount" |
| | | prop="paymentRecordAmount" |
| | | show-overflow-tooltip> |
| | | <template #default="{ row, column }"> |
| | | <el-text type="danger"> |
| | | {{ formattedNumber(row, column, row.payableAmount) }} |
| | | {{ formattedNumber(row, column, row.paymentRecordAmount) }} |
| | | </el-text> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" |
| | | align="center" |
| | | width="90" |
| | | fixed="right"> |
| | | <template #default="{ row }"> |
| | | <el-button link |
| | | type="primary" |
| | | @click.stop="openRecordDialog(row)">æµæ°´</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- ä¾åºå忬¾æµæ°´ç»´æ¤ --> |
| | | <PaymentRecordDialog v-model:visible="recordDialogVisible" |
| | | title="ä¾åºå忬¾æµæ°´" |
| | | :party-type="2" |
| | | :party-id="recordPartyId" |
| | | :party-name="recordPartyName" |
| | | :direction="2" |
| | | @changed="getList" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | paymentRecordList, |
| | | } from "@/api/procurementManagement/paymentLedger.js"; |
| | | import Pagination from "../../../components/PIMTable/Pagination.vue"; |
| | | import PaymentRecordDialog from "@/components/PaymentRecordDialog/index.vue"; |
| | | |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | |
| | | const isShowSummary = ref(true); |
| | | const { searchForm } = toRefs(data); |
| | | const currentSupplierId = ref(""); |
| | | // 忬¾æµæ°´å¼¹çª |
| | | const recordDialogVisible = ref(false); |
| | | const recordPartyId = ref(""); |
| | | const recordPartyName = ref(""); |
| | | |
| | | const openRecordDialog = row => { |
| | | recordPartyId.value = row.supplierId; |
| | | recordPartyName.value = row.supplierName || ""; |
| | | recordDialogVisible.value = true; |
| | | }; |
| | | const rowClick = row => { |
| | | currentSupplierId.value = row.supplierId; |
| | | sonPage.current = 1; |
| | |
| | | return params ? parseFloat(params).toFixed(2) : 0; |
| | | }, |
| | | }, |
| | | { |
| | | label: "éè´§éé¢(å
)", |
| | | prop: "returnAmount", |
| | | width: 200, |
| | | formatData: params => { |
| | | return params ? parseFloat(params).toFixed(2) : 0; |
| | | }, |
| | | }, |
| | | // 徿¥æ¹ç»´åº¦åè®¡ï¼æç»åè¡åå¼ï¼æ
ä¸åä¸åè®¡è¡ |
| | | // { |
| | | // label: "忬¾éé¢(å
)", |
| | | // prop: "receiptAmount", |
| | | // width: 200, |
| | | // formatData: params => { |
| | | // return params ? parseFloat(params).toFixed(2) : 0; |
| | | // }, |
| | | // }, |
| | | // { |
| | | // label: "éè´§éé¢(å
)", |
| | | // prop: "returnAmount", |
| | | // width: 200, |
| | | // formatData: params => { |
| | | // return params ? parseFloat(params).toFixed(2) : 0; |
| | | // }, |
| | | // }, |
| | | { |
| | | label: "åºä»éé¢(å
)", |
| | | dataType: "slot", |
| | | width: 200, |
| | | prop: "payableAmount", |
| | | prop: "paymentRecordAmount", |
| | | slot: "payableAmountSlot", |
| | | }, |
| | | ]); |
| | |
| | | const summarizeMainTable = param => { |
| | | return proxy.summarizeTable( |
| | | param, |
| | | ["contractAmounts", "paymentAmount", "returnAmount", "payableAmount"], |
| | | ["contractAmounts", "paymentAmount", "receiptAmount", "returnAmount", "payableAmount"], |
| | | { |
| | | ticketsNum: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | futureTickets: { noDecimal: true }, // ä¸ä¿çå°æ° |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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.applicationNo" |
| | | 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-select v-model="searchForm.supplierId" |
| | | placeholder="è¯·éæ©" |
| | | filterable |
| | | clearable |
| | | style="width: 240px" |
| | | @change="handleQuery"> |
| | | <el-option v-for="item in supplierOptions" |
| | | :key="item.id" |
| | | :label="item.supplierName" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æï¼"> |
| | | <el-select v-model="searchForm.status" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 160px" |
| | | @change="handleQuery"> |
| | | <el-option label="è稿" |
| | | :value="0" /> |
| | | <el-option label="å·²çæè®¢å" |
| | | :value="1" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ç³è¯·æ¥æï¼"> |
| | | <el-date-picker v-model="searchForm.applyDate" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | @change="changeDaterange" /> |
| | | </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 type="primary" |
| | | @click="openForm('add')">æ°å¢ç³è¯·å</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete()">å é¤</el-button> |
| | | </div> |
| | | <el-table :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | @selection-change="handleSelectionChange" |
| | | :row-key="(row) => row.id" |
| | | show-summary |
| | | :summary-method="summarizeMainTable" |
| | | height="calc(100vh - 21.5em)"> |
| | | <el-table-column align="center" |
| | | type="selection" |
| | | width="55" |
| | | :selectable="row => row.status === 0" /> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="ç³è¯·åå·" |
| | | prop="applicationNo" |
| | | width="170" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ä¾åºååç§°" |
| | | prop="supplierName" |
| | | width="200" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="项ç®åç§°" |
| | | prop="projectName" |
| | | width="280" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="éå®ååå·" |
| | | prop="salesContractNo" |
| | | width="170" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ç³è¯·äºº" |
| | | prop="applicantName" |
| | | width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ç³è¯·æ¥æ" |
| | | prop="applyDate" |
| | | width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ææå°è´§æ¥æ" |
| | | prop="expectedArrivalDate" |
| | | width="130" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ååéé¢(å
)" |
| | | prop="contractAmount" |
| | | width="140" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="仿¬¾æ¹å¼" |
| | | prop="paymentMethod" |
| | | width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ç¶æ" |
| | | prop="status" |
| | | width="110" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.status === 1 ? 'success' : 'info'" |
| | | size="small"> |
| | | {{ statusText[scope.row.status] || '--' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="夿³¨" |
| | | prop="remarks" |
| | | width="200" |
| | | show-overflow-tooltip /> |
| | | <el-table-column fixed="right" |
| | | label="æä½" |
| | | width="200" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <template v-if="scope.row.status === 0"> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openForm('edit', scope.row)">ç¼è¾</el-button> |
| | | <el-button link |
| | | type="primary" |
| | | @click="handleConvert(scope.row)">转订å</el-button> |
| | | <el-button link |
| | | type="danger" |
| | | @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </template> |
| | | <el-button v-else |
| | | link |
| | | type="primary" |
| | | @click="openForm('detail', 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" /> |
| | | </div> |
| | | <FormDialog v-model="dialogFormVisible" |
| | | :title="dialogTitle" |
| | | :width="'70%'" |
| | | :operation-type="operationType" |
| | | @close="closeDia" |
| | | @confirm="submitForm" |
| | | @cancel="closeDia"> |
| | | <el-form :model="form" |
| | | :disabled="isDetail" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç³è¯·åå·ï¼" |
| | | prop="applicationNo"> |
| | | <el-input v-model="form.applicationNo" |
| | | placeholder="ä¿ååèªå¨çæ" |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç³è¯·æ¥æï¼" |
| | | prop="applyDate"> |
| | | <el-date-picker style="width: 100%" |
| | | v-model="form.applyDate" |
| | | 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="supplierId"> |
| | | <el-select v-model="form.supplierId" |
| | | placeholder="è¯·éæ©" |
| | | filterable |
| | | clearable |
| | | style="width: 100%"> |
| | | <el-option v-for="item in supplierList" |
| | | :key="item.id" |
| | | :label="item.supplierName" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="项ç®åç§°" |
| | | prop="projectName"> |
| | | <el-input v-model="form.projectName" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éå®ååå·ï¼" |
| | | prop="salesLedgerId"> |
| | | <el-select v-model="form.salesLedgerId" |
| | | placeholder="è¯·éæ©" |
| | | filterable |
| | | clearable |
| | | style="width: 100%" |
| | | @change="salesLedgerChange"> |
| | | <el-option v-for="item in salesContractList" |
| | | :key="item.id" |
| | | :label="item.salesContractNo" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç³è¯·äººï¼" |
| | | prop="applicantId"> |
| | | <el-select v-model="form.applicantId" |
| | | placeholder="ä¸éåé»è®¤ä¸ºå½åç»å½ç¨æ·" |
| | | filterable |
| | | clearable |
| | | style="width: 100%"> |
| | | <el-option v-for="item in userList" |
| | | :key="item.userId" |
| | | :label="item.nickName" |
| | | :value="item.userId" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="8"> |
| | | <el-form-item label="ææå°è´§æ¥æï¼" |
| | | prop="expectedArrivalDate"> |
| | | <el-date-picker style="width: 100%" |
| | | v-model="form.expectedArrivalDate" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="ååéé¢(å
)ï¼" |
| | | prop="contractAmount"> |
| | | <el-input-number v-model="form.contractAmount" |
| | | :precision="2" |
| | | :step="0.1" |
| | | :min="0" |
| | | placeholder="请è¾å
¥" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="仿¬¾æ¹å¼ï¼" |
| | | prop="paymentMethod"> |
| | | <el-input v-model="form.paymentMethod" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-form-item label="产åä¿¡æ¯ï¼"> |
| | | <el-button v-if="!isDetail" |
| | | type="primary" |
| | | @click="openProductForm('add')">æ·»å </el-button> |
| | | <el-button v-if="!isDetail" |
| | | plain |
| | | type="danger" |
| | | @click="deleteProduct">å é¤</el-button> |
| | | </el-form-item> |
| | | </el-row> |
| | | <el-table :data="productData" |
| | | border |
| | | @selection-change="productSelected" |
| | | show-summary |
| | | :summary-method="summarizeProTable"> |
| | | <el-table-column align="center" |
| | | type="selection" |
| | | width="55" |
| | | :selectable="() => !isDetail" /> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="产å大类" |
| | | prop="productCategory" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="specificationModel" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="åä½" |
| | | prop="unit" |
| | | width="70" /> |
| | | <el-table-column label="æ°é" |
| | | prop="quantity" |
| | | width="80" /> |
| | | <el-table-column label="ç¨ç(%)" |
| | | prop="taxRate" |
| | | width="80" /> |
| | | <el-table-column label="å«ç¨åä»·(å
)" |
| | | prop="taxInclusiveUnitPrice" |
| | | width="120" |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="å«ç¨æ»ä»·(å
)" |
| | | prop="taxInclusiveTotalPrice" |
| | | width="120" |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="ä¸å«ç¨æ»ä»·(å
)" |
| | | prop="taxExclusiveTotalPrice" |
| | | width="130" |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="å票类å" |
| | | prop="invoiceType" |
| | | width="110" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="æ¯å¦è´¨æ£" |
| | | prop="isChecked" |
| | | width="90"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.isChecked ? 'success' : 'info'" |
| | | size="small"> |
| | | {{ scope.row.isChecked ? 'æ¯' : 'å¦' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="夿³¨" |
| | | prop="remark" |
| | | show-overflow-tooltip /> |
| | | <el-table-column v-if="!isDetail" |
| | | fixed="right" |
| | | label="æä½" |
| | | width="80" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openProductForm('edit', scope.row, scope.$index)">ç¼è¾ |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨ï¼" |
| | | prop="remarks"> |
| | | <el-input v-model="form.remarks" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | type="textarea" |
| | | :rows="2" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | <FormDialog v-model="productFormVisible" |
| | | :title="productOperationType === 'add' ? 'æ°å¢äº§å' : 'ç¼è¾äº§å'" |
| | | :width="'40%'" |
| | | :operation-type="productOperationType" |
| | | @close="closeProductDia" |
| | | @confirm="submitProduct" |
| | | @cancel="closeProductDia"> |
| | | <el-form :model="productForm" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="productRules" |
| | | ref="productFormRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="产å大类ï¼" |
| | | prop="productId"> |
| | | <el-tree-select v-model="productForm.productId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | | check-strictly |
| | | @change="getModels" |
| | | :data="productOptions" |
| | | :render-after-expand="false" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="è§æ ¼åå·ï¼" |
| | | prop="productModelId"> |
| | | <el-select v-model="productForm.productModelId" |
| | | placeholder="è¯·éæ©" |
| | | filterable |
| | | clearable |
| | | style="width: 100%" |
| | | @change="getProductModel"> |
| | | <el-option v-for="item in modelOptions" |
| | | :key="item.id" |
| | | :label="item.model" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åä½ï¼" |
| | | prop="unit"> |
| | | <el-input v-model="productForm.unit" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç¨ç(%)ï¼" |
| | | prop="taxRate"> |
| | | <el-select v-model="productForm.taxRate" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="calcTotals"> |
| | | <el-option v-for="dict in tax_rate" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å«ç¨åä»·(å
)ï¼" |
| | | prop="taxInclusiveUnitPrice"> |
| | | <el-input-number v-model="productForm.taxInclusiveUnitPrice" |
| | | :precision="2" |
| | | :step="0.1" |
| | | :min="0" |
| | | style="width: 100%" |
| | | @change="calcTotals" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ°éï¼" |
| | | prop="quantity"> |
| | | <el-input-number v-model="productForm.quantity" |
| | | :precision="2" |
| | | :step="0.1" |
| | | :min="0" |
| | | placeholder="请è¾å
¥" |
| | | style="width: 100%" |
| | | @change="calcTotals" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å«ç¨æ»ä»·(å
)ï¼" |
| | | prop="taxInclusiveTotalPrice"> |
| | | <el-input-number v-model="productForm.taxInclusiveTotalPrice" |
| | | :precision="2" |
| | | disabled |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¸å«ç¨æ»ä»·(å
)ï¼" |
| | | prop="taxExclusiveTotalPrice"> |
| | | <el-input-number v-model="productForm.taxExclusiveTotalPrice" |
| | | :precision="2" |
| | | disabled |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å票类åï¼" |
| | | prop="invoiceType"> |
| | | <el-select v-model="productForm.invoiceType" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 100%"> |
| | | <el-option label="墿®ç¥¨" |
| | | value="墿®ç¥¨" /> |
| | | <el-option label="å¢ä¸ç¥¨" |
| | | value="å¢ä¸ç¥¨" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¯å¦è´¨æ£ï¼" |
| | | prop="isChecked"> |
| | | <el-radio-group v-model="productForm.isChecked"> |
| | | <el-radio label="æ¯" |
| | | :value="true" /> |
| | | <el-radio label="å¦" |
| | | :value="false" /> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨ï¼" |
| | | prop="remark"> |
| | | <el-input v-model="productForm.remark" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { |
| | | ref, |
| | | reactive, |
| | | toRefs, |
| | | computed, |
| | | getCurrentInstance, |
| | | nextTick, |
| | | onMounted, |
| | | } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import dayjs from "dayjs"; |
| | | import router from "@/router"; |
| | | import usePermissionStore from "@/store/modules/permission"; |
| | | import { |
| | | applicationList, |
| | | getApplicationById, |
| | | addApplication, |
| | | editApplication, |
| | | delApplication, |
| | | convertToOrder, |
| | | } from "@/api/procurementManagement/purchaseApplication.js"; |
| | | import { |
| | | getSalesNo, |
| | | getOptions, |
| | | } from "@/api/procurementManagement/procurementLedger.js"; |
| | | import { modelList, productTreeList } from "@/api/basicData/product.js"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const { tax_rate } = proxy.useDict("tax_rate"); |
| | | const permissionStore = usePermissionStore(); |
| | | |
| | | const statusText = { |
| | | 0: "è稿", |
| | | 1: "å·²çæè®¢å", |
| | | }; |
| | | |
| | | const tableData = ref([]); |
| | | const productData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const productSelectedRows = ref([]); |
| | | const supplierOptions = ref([]); |
| | | const supplierList = ref([]); |
| | | const salesContractList = ref([]); |
| | | const userList = ref([]); |
| | | const productOptions = ref([]); |
| | | const modelOptions = ref([]); |
| | | const tableLoading = ref(false); |
| | | const dialogFormVisible = ref(false); |
| | | const productFormVisible = ref(false); |
| | | const operationType = ref(""); |
| | | const productOperationType = ref(""); |
| | | const productOperationIndex = ref(""); |
| | | const currentId = ref(""); |
| | | const total = ref(0); |
| | | const page = reactive({ current: 1, size: 10 }); |
| | | |
| | | const isDetail = computed(() => operationType.value === "detail"); |
| | | const dialogTitle = computed(() => { |
| | | if (operationType.value === "add") return "æ°å¢éè´ç³è¯·"; |
| | | if (operationType.value === "edit") return "ç¼è¾éè´ç³è¯·"; |
| | | return "éè´ç³è¯·è¯¦æ
"; |
| | | }); |
| | | |
| | | const searchForm = reactive({ |
| | | applicationNo: "", |
| | | projectName: "", |
| | | supplierId: "", |
| | | status: "", |
| | | applyDate: null, |
| | | startDate: undefined, |
| | | endDate: undefined, |
| | | }); |
| | | |
| | | const data = reactive({ |
| | | form: { |
| | | id: "", |
| | | applicationNo: "", |
| | | supplierId: "", |
| | | projectName: "", |
| | | salesContractNo: "", |
| | | salesLedgerId: "", |
| | | applicantId: "", |
| | | applyDate: "", |
| | | expectedArrivalDate: "", |
| | | contractAmount: "", |
| | | paymentMethod: "", |
| | | remarks: "", |
| | | }, |
| | | rules: { |
| | | applyDate: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { form, rules } = toRefs(data); |
| | | |
| | | const productFormData = reactive({ |
| | | productForm: { |
| | | productId: "", |
| | | productCategory: "", |
| | | productModelId: "", |
| | | specificationModel: "", |
| | | unit: "", |
| | | quantity: "", |
| | | taxRate: "", |
| | | taxInclusiveUnitPrice: "", |
| | | taxInclusiveTotalPrice: "", |
| | | taxExclusiveTotalPrice: "", |
| | | invoiceType: "", |
| | | isChecked: false, |
| | | remark: "", |
| | | }, |
| | | 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" }], |
| | | taxRate: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | taxInclusiveUnitPrice: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | }, |
| | | }); |
| | | const { productForm, productRules } = toRefs(productFormData); |
| | | |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | if (cellValue === null || cellValue === undefined || cellValue === "") { |
| | | return "--"; |
| | | } |
| | | return Number(cellValue).toFixed(2); |
| | | }; |
| | | |
| | | const changeDaterange = value => { |
| | | if (value) { |
| | | searchForm.startDate = dayjs(value[0]).format("YYYY-MM-DD"); |
| | | searchForm.endDate = dayjs(value[1]).format("YYYY-MM-DD"); |
| | | } else { |
| | | searchForm.startDate = undefined; |
| | | searchForm.endDate = undefined; |
| | | } |
| | | handleQuery(); |
| | | }; |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const paginationChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | const { applyDate, ...rest } = searchForm; |
| | | applicationList({ ...rest, pageNum: page.current, pageSize: page.size }) |
| | | .then(res => { |
| | | const rows = res.rows || res.data?.rows || res.data?.records || []; |
| | | tableData.value = rows; |
| | | total.value = res.total ?? res.data?.total ?? 0; |
| | | }) |
| | | .catch(() => { |
| | | tableData.value = []; |
| | | total.value = 0; |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | |
| | | const productSelected = selection => { |
| | | productSelectedRows.value = selection; |
| | | }; |
| | | |
| | | const summarizeMainTable = param => { |
| | | return proxy.summarizeTable(param, ["contractAmount"]); |
| | | }; |
| | | |
| | | const summarizeProTable = param => { |
| | | return proxy.summarizeTable(param, [ |
| | | "taxInclusiveUnitPrice", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice", |
| | | ]); |
| | | }; |
| | | |
| | | // ä¾åºå䏿ï¼çéç¨å
¨éï¼è¡¨åä»
å¯éç½ååä¾åºåï¼ä¸éè´å°è´¦ä¸è´ï¼ |
| | | const getSupplierOptions = async () => { |
| | | const res = await getOptions(); |
| | | const list = res.data || []; |
| | | supplierOptions.value = list; |
| | | supplierList.value = list.filter(item => item.isWhite === 0); |
| | | }; |
| | | |
| | | const getSalesContractList = async () => { |
| | | const res = await getSalesNo(); |
| | | salesContractList.value = Array.isArray(res) ? res : res?.data || []; |
| | | }; |
| | | |
| | | const getUserList = async () => { |
| | | const res = await userListNoPage(); |
| | | userList.value = res.data || []; |
| | | }; |
| | | |
| | | const getProductOptions = async () => { |
| | | const res = await productTreeList(); |
| | | productOptions.value = convertIdToValue(res || []); |
| | | }; |
| | | |
| | | function convertIdToValue(list) { |
| | | return list.map(item => { |
| | | const { id, children, ...rest } = item; |
| | | const newItem = { ...rest, value: id }; |
| | | if (children && children.length > 0) { |
| | | newItem.children = convertIdToValue(children); |
| | | } |
| | | return newItem; |
| | | }); |
| | | } |
| | | |
| | | const findNodeLabelById = (nodes, value) => { |
| | | for (const node of nodes) { |
| | | if (node.value === value) { |
| | | return node.label; |
| | | } |
| | | if (node.children && node.children.length > 0) { |
| | | const found = findNodeLabelById(node.children, value); |
| | | if (found) return found; |
| | | } |
| | | } |
| | | return ""; |
| | | }; |
| | | |
| | | const findNodeValueByLabel = (nodes, label) => { |
| | | for (const node of nodes) { |
| | | if (node.label === label) { |
| | | return node.value; |
| | | } |
| | | if (node.children && node.children.length > 0) { |
| | | const found = findNodeValueByLabel(node.children, label); |
| | | if (found) return found; |
| | | } |
| | | } |
| | | return ""; |
| | | }; |
| | | |
| | | const getModels = value => { |
| | | if (!value) { |
| | | productForm.value.productCategory = ""; |
| | | modelOptions.value = []; |
| | | return Promise.resolve([]); |
| | | } |
| | | productForm.value.productCategory = findNodeLabelById( |
| | | productOptions.value, |
| | | value |
| | | ); |
| | | return modelList({ id: value }).then(res => { |
| | | modelOptions.value = res || []; |
| | | return res; |
| | | }); |
| | | }; |
| | | |
| | | const getProductModel = value => { |
| | | const matched = modelOptions.value.find(item => item.id === value); |
| | | if (matched) { |
| | | productForm.value.specificationModel = matched.model; |
| | | productForm.value.unit = matched.unit; |
| | | } else { |
| | | productForm.value.specificationModel = ""; |
| | | productForm.value.unit = ""; |
| | | } |
| | | }; |
| | | |
| | | // å«ç¨æ»ä»· = å«ç¨åä»· à æ°éï¼ä¸å«ç¨æ»ä»·ç±å«ç¨æ»ä»·ä¸ç¨çåç® |
| | | const calcTotals = () => { |
| | | const { taxInclusiveUnitPrice, quantity, taxRate } = productForm.value; |
| | | if (!taxInclusiveUnitPrice && taxInclusiveUnitPrice !== 0) return; |
| | | if (!quantity && quantity !== 0) return; |
| | | productForm.value.taxInclusiveTotalPrice = |
| | | proxy.calculateTaxIncludeTotalPrice(taxInclusiveUnitPrice, quantity); |
| | | if (taxRate) { |
| | | productForm.value.taxExclusiveTotalPrice = |
| | | proxy.calculateTaxExclusiveTotalPrice( |
| | | productForm.value.taxInclusiveTotalPrice, |
| | | taxRate |
| | | ); |
| | | } |
| | | }; |
| | | |
| | | const openProductForm = async (type, row, index) => { |
| | | productOperationType.value = type; |
| | | productOperationIndex.value = index; |
| | | productForm.value = {}; |
| | | proxy.resetForm("productFormRef"); |
| | | productFormVisible.value = true; |
| | | |
| | | if (productOptions.value.length === 0) { |
| | | await getProductOptions(); |
| | | } |
| | | await nextTick(); |
| | | |
| | | if (type === "add") { |
| | | productForm.value.isChecked = false; |
| | | return; |
| | | } |
| | | |
| | | productForm.value = { ...row }; |
| | | if (!productForm.value.productId && productForm.value.productCategory) { |
| | | productForm.value.productId = findNodeValueByLabel( |
| | | productOptions.value, |
| | | productForm.value.productCategory |
| | | ); |
| | | } |
| | | if (productForm.value.productId) { |
| | | await getModels(productForm.value.productId); |
| | | await nextTick(); |
| | | if (productForm.value.productModelId) { |
| | | getProductModel(productForm.value.productModelId); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const submitProduct = () => { |
| | | proxy.$refs["productFormRef"].validate(valid => { |
| | | if (!valid) return; |
| | | if (productOperationType.value === "add") { |
| | | productData.value.push({ ...productForm.value }); |
| | | } else { |
| | | productData.value[productOperationIndex.value] = { |
| | | ...productForm.value, |
| | | }; |
| | | } |
| | | closeProductDia(); |
| | | }); |
| | | }; |
| | | |
| | | const deleteProduct = () => { |
| | | if (productSelectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | productData.value = productData.value.filter( |
| | | item => !productSelectedRows.value.includes(item) |
| | | ); |
| | | productSelectedRows.value = []; |
| | | }; |
| | | |
| | | const closeProductDia = () => { |
| | | proxy.resetForm("productFormRef"); |
| | | productFormVisible.value = false; |
| | | }; |
| | | |
| | | const salesLedgerChange = value => { |
| | | const matched = salesContractList.value.find(item => item.id === value); |
| | | form.value.salesContractNo = matched ? matched.salesContractNo : ""; |
| | | }; |
| | | |
| | | const openForm = async (type, row) => { |
| | | operationType.value = type; |
| | | currentId.value = row?.id || ""; |
| | | proxy.resetForm("formRef"); |
| | | form.value = { |
| | | id: "", |
| | | applicationNo: "", |
| | | supplierId: "", |
| | | projectName: "", |
| | | salesContractNo: "", |
| | | salesLedgerId: "", |
| | | applicantId: "", |
| | | applyDate: dayjs().format("YYYY-MM-DD"), |
| | | expectedArrivalDate: "", |
| | | contractAmount: "", |
| | | paymentMethod: "", |
| | | remarks: "", |
| | | }; |
| | | productData.value = []; |
| | | productSelectedRows.value = []; |
| | | |
| | | try { |
| | | await Promise.all([ |
| | | getSupplierOptions(), |
| | | getSalesContractList(), |
| | | getUserList(), |
| | | getProductOptions(), |
| | | ]); |
| | | } catch (error) { |
| | | proxy.$modal.msgError("å è½½åºç¡æ°æ®å¤±è´¥"); |
| | | return; |
| | | } |
| | | |
| | | if (type === "add") { |
| | | dialogFormVisible.value = true; |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | const res = await getApplicationById({ id: row.id }); |
| | | form.value = { ...(res.data || {}), id: row.id }; |
| | | productData.value = res.data?.productData || []; |
| | | } catch (error) { |
| | | proxy.$modal.msgError("å è½½éè´ç³è¯·è¯¦æ
失败"); |
| | | return; |
| | | } |
| | | dialogFormVisible.value = true; |
| | | }; |
| | | |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | |
| | | // åªæäº¤å端å
许çåæ®µï¼èªå¨å段ï¼åå·ãç¶æãç§æ·çï¼ä¸å¾ä¸ä¼ |
| | | const buildPayload = () => { |
| | | const payload = { |
| | | supplierId: form.value.supplierId || null, |
| | | projectName: form.value.projectName, |
| | | salesContractNo: form.value.salesContractNo, |
| | | salesLedgerId: form.value.salesLedgerId || null, |
| | | applyDate: form.value.applyDate, |
| | | expectedArrivalDate: form.value.expectedArrivalDate || null, |
| | | contractAmount: |
| | | form.value.contractAmount === "" ? null : form.value.contractAmount, |
| | | paymentMethod: form.value.paymentMethod, |
| | | remarks: form.value.remarks, |
| | | productData: productData.value.map( |
| | | ({ id, purchaseApplicationId, ...rest }) => rest |
| | | ), |
| | | }; |
| | | // ç³è¯·äººç空表示ç±å端åå½åç»å½ç¨æ· |
| | | if (form.value.applicantId) { |
| | | payload.applicantId = form.value.applicantId; |
| | | } |
| | | return payload; |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(async valid => { |
| | | if (!valid) return; |
| | | const payload = buildPayload(); |
| | | try { |
| | | if (operationType.value === "add") { |
| | | await addApplication(payload); |
| | | } else { |
| | | await editApplication({ id: currentId.value, ...payload }); |
| | | } |
| | | proxy.$modal.msgSuccess("ä¿åæå"); |
| | | closeDia(); |
| | | getList(); |
| | | } catch (error) { |
| | | // é误信æ¯ç± request æ¦æªå¨ç»ä¸æç¤º |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const handleDelete = row => { |
| | | let ids = []; |
| | | if (row) { |
| | | ids = [row.id]; |
| | | } else if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value.map(item => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(async () => { |
| | | await delApplication(ids); |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .catch(() => {}); |
| | | }; |
| | | |
| | | const handleConvert = row => { |
| | | ElMessageBox.confirm( |
| | | `确认å°ç³è¯·åã${row.applicationNo}ã转为éè´è®¢ååï¼è½¬è®¢ååå°èªå¨æäº¤éè´å®¡æ¹ã`, |
| | | "转订å", |
| | | { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | } |
| | | ) |
| | | .then(async () => { |
| | | const res = await convertToOrder(row.id); |
| | | getList(); |
| | | ElMessageBox.confirm( |
| | | `转订åæåï¼å·²çæéè´å°è´¦ï¼idï¼${res.data}ï¼ãæ¯å¦åå¾éè´å°è´¦æ¥çï¼`, |
| | | "æç¤º", |
| | | { |
| | | confirmButtonText: "å徿¥ç", |
| | | cancelButtonText: "ç卿¬é¡µ", |
| | | type: "success", |
| | | } |
| | | ) |
| | | .then(() => { |
| | | const path = findLedgerPath(permissionStore.sidebarRouters); |
| | | if (path) { |
| | | router.push(path); |
| | | } else { |
| | | ElMessage.info("请åå¾ãéè´å°è´¦ãæ¥ççæç订å"); |
| | | } |
| | | }) |
| | | .catch(() => {}); |
| | | }) |
| | | .catch(() => {}); |
| | | }; |
| | | |
| | | // ä»ä¾§è¾¹æ èåä¸å®ä½éè´å°è´¦è·¯ç±ï¼æ¾ä¸å°æ¶ä¸è·³è½¬ä»
æç¤º |
| | | const findLedgerPath = (routes, prefix = "") => { |
| | | for (const route of routes || []) { |
| | | const fullPath = String(route.path || "").startsWith("/") |
| | | ? route.path |
| | | : `${prefix}/${route.path || ""}`; |
| | | if (route.meta?.title === "éè´å°è´¦") { |
| | | return fullPath; |
| | | } |
| | | const found = findLedgerPath(route.children, fullPath); |
| | | if (found) return found; |
| | | } |
| | | return ""; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | getSupplierOptions(); |
| | | }); |
| | | </script> |
| | |
| | | }); |
| | | // ä½¿ç¨ Promise.all å¤çææå¼æ¥è¯·æ± |
| | | const processedOrders = await Promise.all(response.data.records.map(async (order) => { |
| | | // çå¾
弿¥è·å产åè®°å½ |
| | | // çå¾
弿¥è·å产åè®°å½ï¼æéè´å°è´¦idç²¾ç¡®åæ¾ï¼ååå·å¯è½éå¤/ä¸ºç©ºï¼ |
| | | const productRes = await selectProductRecordListByPuechaserId({ |
| | | purchaseContractNumber: order.purchaseContractNumber |
| | | purchaseLedgerId: order.id |
| | | }); |
| | | |
| | | // ç¡®ä¿ productRes.data åå¨ |
| | |
| | | { |
| | | try { |
| | | loadingProducts.value = true |
| | | // æ ¹æ®ååæ¥è¯¢äº§åè®°å½ |
| | | // æ ¹æ®éè´å°è´¦idæ¥è¯¢äº§åè®°å½ |
| | | const productRes = await selectProductRecordListByPuechaserId({ |
| | | purchaseContractNumber: receiptForm.value.purchaseContractNumber |
| | | purchaseLedgerId: receiptForm.value.purchaseLedgerId |
| | | }); |
| | | console.log('productRes:', productRes) |
| | | operationType.value = 'add' |
| | |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <el-form :model="searchForm" :inline="true"> |
| | | <el-form-item label="éå®è®¢åå·ï¼"> |
| | | <el-form-item label="åè´§åå·ï¼"> |
| | | <el-input |
| | | v-model="searchForm.shippingNo" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | prefix-icon="Search" |
| | | style="width: 200px" |
| | | @change="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="éå®ååå·ï¼"> |
| | | <el-input |
| | | v-model="searchForm.salesContractNo" |
| | | placeholder="请è¾å
¥" |
| | |
| | | <el-form-item label="车çå·ï¼"> |
| | | <el-input |
| | | v-model="searchForm.shippingCarNumber" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | prefix-icon="Search" |
| | | style="width: 200px" |
| | | @change="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="å¿«éåå·ï¼"> |
| | | <el-input |
| | | v-model="searchForm.expressNumber" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | prefix-icon="Search" |
| | |
| | | border |
| | | v-loading="tableLoading" |
| | | @selection-change="handleSelectionChange" |
| | | :row-key="(row) => row.id" |
| | | :row-key="(row) => `${row.source || 'shipping'}-${row.stockOutRecordId ?? row.id}`" |
| | | style="width: 100%" |
| | | height="calc(100vh - 21.5em)" |
| | | > |
| | | <el-table-column align="center" type="selection" width="55" /> |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column |
| | | label="éå®è®¢å" |
| | | prop="salesContractNo" |
| | | show-overflow-tooltip |
| | | align="center" |
| | | type="selection" |
| | | :selectable="isRowSelectable" |
| | | width="55" |
| | | /> |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column label="æ¥æº" prop="source" align="center" width="100"> |
| | | <template #default="scope"> |
| | | <el-tag |
| | | :type="isOilOutRow(scope.row) ? 'success' : 'info'" |
| | | size="small" |
| | | > |
| | | {{ isOilOutRow(scope.row) ? "æ²¹ååºåº" : "åè´§å" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="å货订åå·" |
| | | prop="shippingNo" |
| | |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="客æ·å¯¹æ¥äºº" |
| | | prop="contactPerson" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="对æ¥äººçµè¯" |
| | | prop="contactPhone" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="产ååç§°" |
| | | prop="productName" |
| | | show-overflow-tooltip |
| | |
| | | <el-table-column |
| | | label="è§æ ¼åå·" |
| | | prop="specificationModel" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column label="æ¹å·" show-overflow-tooltip> |
| | | <!-- æ²¹ååºåºè¡çæ¹å·æ¯ outBatchNoï¼batch_noï¼ï¼åè´§åè¡æ²¡æè¯¥å段 --> |
| | | <template #default="scope"> |
| | | {{ |
| | | isOilOutRow(scope.row) |
| | | ? scope.row.outBatchNo || "--" |
| | | : scope.row.batchNo || "--" |
| | | }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="åºåºç±»å«" |
| | | prop="outCategory" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column label="å¨ç½å·" prop="tankNo" show-overflow-tooltip /> |
| | | <el-table-column |
| | | label="æ²¹åº" |
| | | prop="oilDepotName" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="å¿«éå
¬å¸" |
| | | prop="expressCompany" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="å¿«éåå·" |
| | | prop="expressNumber" |
| | | label="叿ºå§å" |
| | | prop="driverName" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | |
| | | > |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="åè´§ç±»åï¼" prop="type"> |
| | | <el-select |
| | | v-model="form.type" |
| | | placeholder="è¯·éæ©åè´§ç±»å" |
| | | style="width: 100%" |
| | | @change="handleShippingTypeChange" |
| | | > |
| | | <el-option label="货车" value="货车" /> |
| | | <el-option label="å¿«é" value="å¿«é" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="åè´§æ¥æï¼" prop="shippingDate"> |
| | | <el-date-picker |
| | | style="width: 100%" |
| | |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24" v-if="form.type === '货车'"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="å货车çå·ï¼" prop="shippingCarNumber"> |
| | | <el-input |
| | | v-model="form.shippingCarNumber" |
| | | placeholder="请è¾å
¥å货车çå·" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24" v-else> |
| | | <el-form-item label="å¿«éå
¬å¸ï¼" prop="expressCompany"> |
| | | <el-input |
| | | v-model="form.expressCompany" |
| | | placeholder="请è¾å
¥å¿«éå
¬å¸" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30" v-if="form.type === 'å¿«é'"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="å¿«éåå·ï¼" prop="expressNumber"> |
| | | <el-input |
| | | v-model="form.expressNumber" |
| | | placeholder="请è¾å
¥å¿«éåå·" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | |
| | | > |
| | | <div v-if="detailRow" class="detail-wrapper"> |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions-item label="éå®è®¢å">{{ |
| | | detailRow.salesContractNo || "--" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="å货订åå·">{{ |
| | | detailRow.shippingNo || "--" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="客æ·åç§°">{{ |
| | | detailRow.customerName || "--" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="客æ·å¯¹æ¥äºº">{{ |
| | | detailRow.contactPerson || "--" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="对æ¥äººçµè¯">{{ |
| | | detailRow.contactPhone || "--" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="产ååç§°">{{ |
| | | detailRow.productName || "--" |
| | |
| | | <el-descriptions-item label="è§æ ¼åå·">{{ |
| | | detailRow.specificationModel || "--" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="åè´§ç±»å">{{ |
| | | detailRow.type || "--" |
| | | <el-descriptions-item label="åºåºç±»å«">{{ |
| | | detailRow.outCategory || "--" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="å¨ç½å·">{{ |
| | | detailRow.tankNo || "--" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ²¹åº">{{ |
| | | detailRow.oilDepotName || "--" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="åè´§æ¥æ">{{ |
| | | detailRow.shippingDate || "--" |
| | |
| | | <el-descriptions-item label="å货车çå·">{{ |
| | | detailRow.shippingCarNumber || "--" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="å¿«éå
¬å¸">{{ |
| | | detailRow.expressCompany || "--" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="å¿«éåå·" :span="2">{{ |
| | | detailRow.expressNumber || "--" |
| | | <el-descriptions-item label="叿ºå§å">{{ |
| | | detailRow.driverName || "--" |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="åºåºåå·" :span="2">{{ |
| | | detailRow.outboundBatches || "--" |
| | |
| | | /> |
| | | <el-table-column |
| | | label="åè´§æ°é" |
| | | prop="deliveryQuantity" |
| | | prop="totalQuantity" |
| | | min-width="120" |
| | | align="center" |
| | | /> |
| | |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | const salesOrderOptions = ref([]); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | |
| | | const dialogFormVisible = ref(false); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | salesContractNo: "", // éå®è®¢åå· |
| | | shippingNo: "", // åè´§åå·ï¼ä¸¤ç±»æ¥æºé½å¹é
ï¼ |
| | | salesContractNo: "", // éå®ååå·ï¼åªå¹é
åè´§åè¡ï¼ |
| | | shippingCarNumber: "", // 车çå· |
| | | expressNumber: "", // å¿«éåå· |
| | | }, |
| | | form: { |
| | | id: null, |
| | | salesContractNo: "", |
| | | customerName: "", |
| | | specificationModel: "", |
| | | productName: "", |
| | | type: "货车", // 货车, å¿«é |
| | | shippingDate: "", |
| | | shippingCarNumber: "", |
| | | expressCompany: "", |
| | | expressNumber: "", // å¿«éåå· |
| | | }, |
| | | rules: { |
| | | salesContractNo: [ |
| | | { required: true, message: "è¯·éæ©éå®è®¢å", trigger: "change" }, |
| | | ], |
| | | customerName: [ |
| | | { required: true, message: "请è¾å
¥å®¢æ·åç§°", trigger: "blur" }, |
| | | ], |
| | | type: [{ required: true, message: "è¯·éæ©åè´§ç±»å", trigger: "change" }], |
| | | shippingDate: [ |
| | | { required: true, message: "è¯·éæ©åè´§æ¶é´", trigger: "change" }, |
| | | ], |
| | | shippingCarNumber: [ |
| | | { |
| | | validator: (_, value, callback) => |
| | | validateShippingCarNumber(value, callback), |
| | | trigger: "blur", |
| | | }, |
| | | ], |
| | | expressCompany: [ |
| | | { |
| | | validator: (_, value, callback) => |
| | | validateExpressCompany(value, callback), |
| | | trigger: "blur", |
| | | }, |
| | | { required: true, message: "请è¾å
¥å货车çå·", trigger: "blur" }, |
| | | ], |
| | | }, |
| | | }); |
| | |
| | | }); |
| | | }; |
| | | |
| | | // éå®è®¢åååæ¶èªå¨å¡«å
客æ·åç§° |
| | | const handleSalesOrderChange = (value) => { |
| | | const selectedOrder = salesOrderOptions.value.find( |
| | | (item) => item.salesContractNo === value |
| | | ); |
| | | if (selectedOrder) { |
| | | form.value.customerName = selectedOrder.customerName; |
| | | } |
| | | }; |
| | | // æ²¹ååºåºè¡æ¥èª stock_out_recordï¼id ä¸ shipping_info 伿å·ï¼ |
| | | // åè´§/å é¤/详æ
çæ¥å£èå齿¯ shipping_infoï¼ä¸è½ç¨äºè¿ç±»è¡ |
| | | const isOilOutRow = (row) => row?.source === "oilOut"; |
| | | const isRowSelectable = (row) => !isOilOutRow(row); |
| | | |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | selectedRows.value = selection; |
| | | selectedRows.value = selection.filter((item) => !isOilOutRow(item)); |
| | | }; |
| | | |
| | | // æå¼å¼¹æ¡ |
| | |
| | | if (type === "edit" && row) { |
| | | form.value = { |
| | | id: row.id ?? null, |
| | | salesContractNo: row.salesContractNo ?? "", |
| | | customerName: row.customerName ?? "", |
| | | type: row.type || "货车", |
| | | shippingDate: row.shippingDate || getCurrentDate(), |
| | | shippingCarNumber: row.shippingCarNumber ?? "", |
| | | expressCompany: row.expressCompany ?? "", |
| | | expressNumber: row.expressNumber ?? "", |
| | | }; |
| | | deliveryFileList.value = row.storageBlobVOs || []; |
| | | } |
| | |
| | | detailRow.value = row || null; |
| | | detailProductList.value = []; |
| | | detailDialogVisible.value = true; |
| | | if (!row?.id) return; |
| | | // æ²¹ååºåºè¡ä¸èµ°åè´§å详æ
æ¥å£ï¼id 伿å·ï¼ï¼ç´æ¥ç¨åè¡¨è¡æ°æ®å±ç¤º |
| | | if (!row?.id || isOilOutRow(row)) return; |
| | | try { |
| | | const res = await getDeliveryDetail(row.id); |
| | | const detailData = res?.data; |
| | |
| | | productName: item.productName ?? row.productName ?? "--", |
| | | specificationModel: |
| | | item.specificationModel ?? item.model ?? row.specificationModel ?? "--", |
| | | deliveryQuantity: |
| | | totalQuantity: |
| | | item.totalQuantity ?? |
| | | row.totalQuantity ?? |
| | | item.deliveryQuantity ?? |
| | | item.quantity ?? |
| | | item.shippingQuantity ?? |
| | |
| | | if (valid) { |
| | | const payload = { |
| | | id: form.value.id, |
| | | type: form.value.type, |
| | | shippingDate: form.value.shippingDate, |
| | | shippingCarNumber: |
| | | form.value.type === "货车" ? form.value.shippingCarNumber : "", |
| | | expressCompany: |
| | | form.value.type === "å¿«é" ? form.value.expressCompany : "", |
| | | expressNumber: |
| | | form.value.type === "å¿«é" ? form.value.expressNumber : "", |
| | | shippingCarNumber: form.value.shippingCarNumber, |
| | | storageBlobDTOs: deliveryFileList.value || [], |
| | | }; |
| | | deductStock(payload).then((res) => { |
| | |
| | | }); |
| | | }; |
| | | |
| | | // åè´§ç±»åæ ¡éªï¼è´§è½¦æ¶è¦æ±è½¦çï¼å¿«éæ¶è¦æ±å¿«éå
¬å¸ |
| | | const validateShippingCarNumber = (value, callback) => { |
| | | if (form.value.type === "货车") { |
| | | if (!value) return callback(new Error("请è¾å
¥å货车çå·")); |
| | | } |
| | | callback(); |
| | | }; |
| | | const validateExpressCompany = (value, callback) => { |
| | | if (form.value.type === "å¿«é") { |
| | | if (!value) return callback(new Error("请è¾å
¥å¿«éå
¬å¸")); |
| | | } |
| | | callback(); |
| | | }; |
| | | |
| | | // åè´§å¾çä¸ä¼ åæ ¡æ£ |
| | | function handleDeliveryBeforeUpload(file) { |
| | | // æ ¡æ£æä»¶ç±»å |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | // åè´§ç±»ååæ¢æ¶æ¸
空对åºå段 |
| | | const handleShippingTypeChange = (val) => { |
| | | if (val === "货车") { |
| | | form.value.expressCompany = ""; |
| | | form.value.expressNumber = ""; |
| | | } else { |
| | | form.value.shippingCarNumber = ""; |
| | | } |
| | | }; |
| | | |
| | | // è·åå®¡æ ¸ç¶æææ¬ |
| | | const getApprovalStatusText = (status) => { |
| | |
| | | :formatter="formattedNumber" |
| | | width="200" /> |
| | | <el-table-column label="忬¾éé¢(å
)" |
| | | prop="receiptPaymentAmount" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" |
| | | width="200" /> |
| | | <el-table-column label="éè´§éé¢(å
)" |
| | | prop="returnAmount" |
| | | prop="receiptRecordAmount" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" |
| | | width="200" /> |
| | |
| | | <el-text type="danger"> |
| | | {{ formattedNumber(row, column, row.receiptableAmount) }} |
| | | </el-text> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" |
| | | align="center" |
| | | width="90" |
| | | fixed="right"> |
| | | <template #default="{ row }"> |
| | | <el-button link |
| | | type="primary" |
| | | @click.stop="openRecordDialog(row)">æµæ°´</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | :formatter="formattedNumber" |
| | | width="200" /> |
| | | <el-table-column label="忬¾éé¢(å
)" |
| | | prop="receiptPaymentAmount" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" |
| | | width="200" /> |
| | | <el-table-column label="éè´§éé¢(å
)" |
| | | prop="returnAmount" |
| | | prop="receiptRecordAmount" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" |
| | | width="200" /> |
| | |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- 客æ·ä»æ¬¾æµæ°´ç»´æ¤ --> |
| | | <PaymentRecordDialog v-model:visible="recordDialogVisible" |
| | | title="客æ·ä»æ¬¾æµæ°´" |
| | | :party-type="1" |
| | | :party-id="recordPartyId" |
| | | :party-name="recordPartyName" |
| | | :direction="1" |
| | | @changed="getList" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | customewTransactionsDetails, |
| | | } from "@/api/salesManagement/indicatorStats.js"; |
| | | import Pagination from "../../../components/PIMTable/Pagination.vue"; |
| | | import PaymentRecordDialog from "@/components/PaymentRecordDialog/index.vue"; |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | | const receiptRecord = ref([]); |
| | |
| | | const customerId = ref(""); |
| | | const { searchForm } = toRefs(data); |
| | | const originReceiptRecord = ref([]); |
| | | // 仿¬¾æµæ°´å¼¹çª |
| | | const recordDialogVisible = ref(false); |
| | | const recordPartyId = ref(""); |
| | | const recordPartyName = ref(""); |
| | | |
| | | const openRecordDialog = row => { |
| | | recordPartyId.value = row.customerId; |
| | | recordPartyName.value = row.customerName || ""; |
| | | recordDialogVisible.value = true; |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | |
| | | const summarizeMainTable = param => { |
| | | return proxy.summarizeTable( |
| | | param, |
| | | [ |
| | | "contractAmounts", |
| | | "receiptPaymentAmount", |
| | | "returnAmount", |
| | | "receiptableAmount", |
| | | ], |
| | | ["contractAmounts", "receiptPaymentAmount", "receiptableAmount"], |
| | | { |
| | | ticketsNum: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | futureTickets: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | |
| | | const summarizeMainTable1 = param => { |
| | | var summarizeTable = proxy.summarizeTable( |
| | | param, |
| | | [ |
| | | "contractAmount", |
| | | "receiptPaymentAmount", |
| | | "returnAmount", |
| | | "receiptableAmount", |
| | | ], |
| | | ["contractAmount", "receiptPaymentAmount", "receiptableAmount"], |
| | | { |
| | | ticketsNum: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | futureTickets: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | |
| | | @change="changeDaterange" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="审æ¹ç¶æï¼"> |
| | | <el-select |
| | | v-model="searchForm.approvalStatus" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 160px" |
| | | @change="handleQuery" |
| | | > |
| | | <el-option |
| | | v-for="item in approvalStatusOptions" |
| | | :key="item" |
| | | :label="item" |
| | | :value="item" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery"> æç´¢ </el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <!-- åæ²¹ / 代卿æä¸¤ä¸ªé¡µç¾ï¼åèªåºå®å¸¦ ledgerType è°åä¸ä¸ªå表æ¥å£ --> |
| | | <el-tabs v-model="activeTab" @tab-change="handleTabChange" class="ledger-tabs"> |
| | | <el-tab-pane label="éå®å°è´¦ï¼åæ²¹ï¼" name="åæ²¹" /> |
| | | <el-tab-pane label="代å¨å°è´¦" name="代å¨" /> |
| | | </el-tabs> |
| | | <div class="table_list"> |
| | | <div class="actions"> |
| | | <div></div> |
| | |
| | | style="width: 100%" |
| | | :summary-method="summarizeMainTable" |
| | | @expand-change="expandChange" |
| | | height="calc(100vh - 18.5em)" |
| | | height="calc(100vh - 21.5em)" |
| | | > |
| | | <el-table-column |
| | | align="center" |
| | |
| | | label="ååéé¢(å
)" |
| | | prop="contractAmount" |
| | | width="220" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" |
| | | /> |
| | | > |
| | | <template #default="{ row, column }"> |
| | | <el-tooltip |
| | | v-if="row.exceedsTrustFund" |
| | | :content="`ååéé¢å·²è¶
åºè¯¥å®¢æ·ä¿¡æåºéï¼ä¿¡æåºéï¼${row.trustFund}ï¼`" |
| | | placement="top" |
| | | > |
| | | <el-text type="danger"> |
| | | {{ formattedNumber(row, column, row.contractAmount) }} |
| | | </el-text> |
| | | </el-tooltip> |
| | | <span v-else> |
| | | {{ formattedNumber(row, column, row.contractAmount) }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="å®é
ååéé¢(å
)" |
| | | prop="netContractAmount" |
| | |
| | | width="120" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="éå®ç±»å" |
| | | prop="ledgerType" |
| | | width="100" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | v-if="activeTab === '代å¨'" |
| | | label="æ²¹åº" |
| | | prop="oilDepotName" |
| | | width="180" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | v-if="activeTab === '代å¨'" |
| | | label="å¨ç½å·" |
| | | prop="tankNo" |
| | | width="140" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column label="审æ¹ç¶æ" width="110" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getApprovalStatusType(row.approvalStatus)" size="small"> |
| | | {{ row.approvalStatus || "-" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="夿³¨" |
| | | prop="remarks" |
| | |
| | | :rules="rules" |
| | | ref="formRef" |
| | | > |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éå®ç±»åï¼" prop="ledgerType"> |
| | | <el-radio-group |
| | | v-model="form.ledgerType" |
| | | :disabled="operationType === 'view'" |
| | | > |
| | | <el-radio value="åæ²¹">åæ²¹</el-radio> |
| | | <el-radio value="代å¨">ååå¨ä½ç½®ï¼ä»£å¨ï¼</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- æ¥ä»·å导å
¥å
¥å£ï¼æ¾å¨è¡¨åé¡¶é¨ï¼éæ©å忾客æ·/ä¸å¡åç --> |
| | | <el-row v-if="operationType === 'add'" style="margin-bottom: 10px"> |
| | | <el-row |
| | | v-if="operationType === 'add' && form.ledgerType !== '代å¨'" |
| | | style="margin-bottom: 10px" |
| | | > |
| | | <el-col :span="24" style="text-align: right"> |
| | | <el-button type="primary" plain @click="openQuotationDialog"> |
| | | ä»é宿¥ä»·å¯¼å
¥ |
| | |
| | | clearable |
| | | :disabled="operationType === 'view'" |
| | | filterable |
| | | @change="loadCustomerTrustFund" |
| | | > |
| | | <el-option |
| | | v-for="item in customerOption" |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <!-- 代å¨ï¼ååå¨ä½ç½®ï¼åªéæ²¹åº+å¨ç½å¹¶æå·¥å¡«ååéé¢ --> |
| | | <el-row v-if="form.ledgerType === '代å¨'" :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ²¹åºï¼" prop="oilDepotId"> |
| | | <el-select |
| | | v-model="form.oilDepotId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | | :disabled="operationType === 'view'" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in oilDepotOptions" |
| | | :key="item.id" |
| | | :label="item.depotName" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å¨ç½å·ï¼" prop="tankId"> |
| | | <el-select |
| | | v-model="form.tankId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | | :disabled="operationType === 'view'" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in tankOptions" |
| | | :key="item.id" |
| | | :label="item.tankNo" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row v-if="form.ledgerType === '代å¨'" :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ååéé¢(å
)ï¼" prop="contractAmount"> |
| | | <el-input-number |
| | | v-model="form.contractAmount" |
| | | :min="0" |
| | | :precision="2" |
| | | :controls="false" |
| | | placeholder="请è¾å
¥" |
| | | :disabled="operationType === 'view'" |
| | | style="width: 100%" |
| | | /> |
| | | <!-- éä¸å®¢æ·åæ¬å°æ¯å¯¹ä¿¡æåºéï¼å®æ¶é¢è§æ¯å¦è¶
é --> |
| | | <el-alert |
| | | v-if="isContractOverTrustFund" |
| | | type="warning" |
| | | show-icon |
| | | :closable="false" |
| | | class="trust-fund-alert" |
| | | :title="`ååéé¢å·²è¶
åºè¯¥å®¢æ·ä¿¡æåºéï¼ä¿¡æåºéï¼${selectedCustomerTrustFund}ï¼`" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row v-if="form.ledgerType !== '代å¨'"> |
| | | <el-form-item label="产åä¿¡æ¯ï¼" prop="entryDate"> |
| | | <el-button |
| | | v-if="operationType !== 'view'" |
| | |
| | | </el-form-item> |
| | | </el-row> |
| | | <el-table |
| | | v-if="form.ledgerType !== '代å¨'" |
| | | :data="productData" |
| | | border |
| | | @selection-change="productSelected" |
| | |
| | | <script setup> |
| | | import { getToken } from "@/utils/auth"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { onMounted, ref, getCurrentInstance } from "vue"; |
| | | import { computed, onMounted, ref, getCurrentInstance } from "vue"; |
| | | import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js"; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import useUserStore from "@/store/modules/user"; |
| | |
| | | import FileUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | | import ImageUpload from "@/components/AttachmentUpload/image/index.vue"; |
| | | import { getCurrentDate } from "@/utils/index.js"; |
| | | import { listCustomer } from "@/api/basicData/customer.js"; |
| | | import { getCustomer, listCustomer } from "@/api/basicData/customer.js"; |
| | | import { allOilDepot } from "@/api/basicData/oilDepot.js"; |
| | | import { allTankInfo } from "@/api/basicData/tankInfo.js"; |
| | | |
| | | const FileList = defineAsyncComponent(() => |
| | | import("@/components/Dialog/FileList.vue") |
| | |
| | | const userStore = useUserStore(); |
| | | const { proxy } = getCurrentInstance(); |
| | | const { tax_rate } = proxy.useDict("tax_rate"); |
| | | // åæ²¹ / 代å¨ä¸¤ä¸ªé¡µç¾ï¼åºå®å¸¦ ledgerType è°åä¸ä¸ªå表æ¥å£ |
| | | const activeTab = ref("åæ²¹"); |
| | | const approvalStatusOptions = ["å¾
审æ¹", "å®¡æ ¸ä¸", "éè¿", "æç»"]; |
| | | // 代å¨è¡¨åï¼æ²¹åºãå¨ç½ä¸æï¼ä¸¤è
äºç¸ç¬ç«ï¼å¨ç½ä¸æå¨æ²¹åºä¸ï¼ |
| | | const oilDepotOptions = ref([]); |
| | | const tankOptions = ref([]); |
| | | // 代å¨è¡¨åï¼éä¸å®¢æ·çä¿¡æåºéï¼ç¨äºååéé¢è¶
é宿¶é¢è§ |
| | | const selectedCustomerTrustFund = ref(null); |
| | | const tableData = ref([]); |
| | | const productData = ref([]); |
| | | const selectedRows = ref([]); |
| | |
| | | entryDate: null, // å½å
¥æ¥æ |
| | | entryDateStart: undefined, |
| | | entryDateEnd: undefined, |
| | | approvalStatus: "", // 审æ¹ç¶æ |
| | | }, |
| | | form: { |
| | | salesContractNo: "", |
| | |
| | | executionDate: "", |
| | | hasProductionRecord: false, |
| | | createTime: "", |
| | | ledgerType: "åæ²¹", // éå®ç±»åï¼åæ²¹ / ä»£å¨ |
| | | oilDepotId: "", // 代å¨ï¼æ²¹åº |
| | | tankId: "", // 代å¨ï¼å¨ç½ |
| | | contractAmount: null, // 代å¨ï¼ååéé¢ç±å端æå·¥å¡« |
| | | }, |
| | | rules: { |
| | | ledgerType: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | salesman: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | customerId: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | entryPerson: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | |
| | | }); |
| | | const { form, rules } = toRefs(data); |
| | | const { form: searchForm } = useFormData(data.searchForm); |
| | | // 代å¨ååéé¢è¶
ä¿¡æåºéï¼å®¢æ·æªç»´æ¤ä¿¡æåºéæ¶ä¸æç¤ºï¼ |
| | | const isContractOverTrustFund = computed(() => { |
| | | const fund = selectedCustomerTrustFund.value; |
| | | if (fund === null || fund === undefined || fund === "") return false; |
| | | const amount = Number(form.value.contractAmount); |
| | | if (!(amount > 0)) return false; |
| | | return amount > Number(fund); |
| | | }); |
| | | // 产å表åå¼¹æ¡æ°æ® |
| | | const productFormVisible = ref(false); |
| | | const productOperationType = ref(""); |
| | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | const { entryDate, ...rest } = searchForm; |
| | | // å°èå´æ¥æåæ®µä¼ éç»å端 |
| | | const params = { ...rest, ...page }; |
| | | // å°èå´æ¥æåæ®µä¼ éç»å端ï¼ledgerType ç±å½å页ç¾å³å® |
| | | const params = { ...rest, ...page, ledgerType: activeTab.value }; |
| | | // ç§»é¤å½å
¥æ¥æçé»è®¤å¼è®¾ç½®ï¼åªä¿çèå´æ¥æå段 |
| | | delete params.entryDate; |
| | | return ledgerListPage(params) |
| | | .then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.records; |
| | | tableData.value = res.records || []; |
| | | tableData.value.map((item) => { |
| | | item.children = []; |
| | | }); |
| | |
| | | |
| | | // æ·»å 表è¡ç±»åæ¹æ³ |
| | | const tableRowClassName = ({ row }) => { |
| | | if (!row.deliveryDate) return ""; |
| | | if (row.isFh) return ""; |
| | | |
| | | let className = ""; |
| | | if (row.deliveryDate && !row.isFh) { |
| | | const diff = row.deliveryDaysDiff; |
| | | if (diff === 15) { |
| | | return "yellow"; |
| | | className = "yellow"; |
| | | } else if (diff === 10) { |
| | | return "pink"; |
| | | className = "pink"; |
| | | } else if (diff === 2) { |
| | | return "purple"; |
| | | className = "purple"; |
| | | } else if (diff < 2) { |
| | | return "red"; |
| | | className = "red"; |
| | | } |
| | | } |
| | | // æ¬ç¬ååéé¢è¶
客æ·ä¿¡æåºéï¼å·¦ä¾§çº¢è¾¹ï¼ä¸è¦çä¸é¢ç交æåºè² |
| | | if (row.exceedsTrustFund) { |
| | | className = className ? `${className} trust-fund-exceed` : "trust-fund-exceed"; |
| | | } |
| | | return className; |
| | | }; |
| | | // å°è´¦å®¡æ¹ç¶æï¼å端维æ¤ï¼ä¸åè´§ç¶æ statusTextMap æ å
³ï¼ |
| | | const getApprovalStatusType = status => { |
| | | const map = { |
| | | å¾
审æ¹: "warning", |
| | | å®¡æ ¸ä¸: "primary", |
| | | éè¿: "success", |
| | | æç»: "danger", |
| | | }; |
| | | return map[status] || "info"; |
| | | }; |
| | | // 页ç¾åæ¢ï¼æ¢ ledgerType éæ°æ¥å表 |
| | | const handleTabChange = () => { |
| | | page.current = 1; |
| | | expandedRowKeys.value = []; |
| | | getList(); |
| | | }; |
| | | // 主表åè®¡æ¹æ³ |
| | | const summarizeMainTable = (param) => { |
| | |
| | | form.value = {}; |
| | | productData.value = []; |
| | | selectedQuotation.value = null; |
| | | selectedCustomerTrustFund.value = null; |
| | | let userLists = await userListNoPage(); |
| | | userList.value = userLists.data; |
| | | listCustomer({ current: -1, size: -1, type: 0 }).then((res) => { |
| | | customerOption.value = res.data.records; |
| | | }); |
| | | // æ²¹åº/å¨ç½ä¸æï¼ä»£å¨ç¨ï¼ï¼ä¸¤è
äºç¸ç¬ç« |
| | | allOilDepot().then((res) => { |
| | | oilDepotOptions.value = res.data || []; |
| | | }); |
| | | allTankInfo().then((res) => { |
| | | tankOptions.value = res.data || []; |
| | | }); |
| | | form.value.entryPerson = userStore.id; |
| | | if (type === "add") { |
| | | // æ°å¢æ¶è®¾ç½®å½å
¥æ¥æä¸ºå½å¤© |
| | | // æ°å¢æ¶é»è®¤è·éå½å页ç¾çéå®ç±»å |
| | | form.value.ledgerType = activeTab.value; |
| | | // å½å
¥æ¥æé»è®¤ä¸ºå½å¤© |
| | | form.value.entryDate = getCurrentDate(); |
| | | // ç¾è®¢æ¥æé»è®¤ä¸ºå½å¤© |
| | | form.value.executionDate = getCurrentDate(); |
| | |
| | | getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => { |
| | | form.value = { ...res }; |
| | | form.value.entryPerson = Number(res.entryPerson); |
| | | productData.value = form.value.productData; |
| | | // åå²åæ®/å端æªè¿åæ¶å
åºä¸ºåæ²¹ï¼å¦åå¿
å¡«æ ¡éªä¼å¡ä½ç¼è¾ |
| | | form.value.ledgerType = form.value.ledgerType || "åæ²¹"; |
| | | // 代卿²¡æäº§åæç» |
| | | productData.value = form.value.productData || []; |
| | | fileList.value = form.value.storageBlobVOs; |
| | | // ç¼è¾æ¶è®¾ç½®èªå¨çæä¸ºfalseï¼å
许æå¨ä¿®æ¹ |
| | | form.value.autoGenerateContractNo = false; |
| | | // åæ¾ä¿¡æåºéï¼ä¾ä»£å¨ååéé¢å®æ¶æ¯å¯¹ |
| | | loadCustomerTrustFund(); |
| | | }); |
| | | } |
| | | // let userAll = await userStore.getInfo() |
| | |
| | | // }); |
| | | form.value.entryDate = getCurrentDate(); // 设置é»è®¤å½å
¥æ¥æä¸ºå½åæ¥æ |
| | | dialogFormVisible.value = true; |
| | | }; |
| | | |
| | | // å该客æ·çä¿¡æåºéï¼ä¾ä»£å¨ååéé¢å®æ¶æ¯å¯¹ï¼å®¢æ·æªç»´æ¤å³ä¸ºç©ºï¼ä¸æç¤ºï¼ |
| | | const loadCustomerTrustFund = () => { |
| | | const id = form.value.customerId; |
| | | if (!id) { |
| | | selectedCustomerTrustFund.value = null; |
| | | return; |
| | | } |
| | | getCustomer(id).then((res) => { |
| | | selectedCustomerTrustFund.value = res?.data?.trustFund ?? null; |
| | | }); |
| | | }; |
| | | |
| | | // æå¼æ¥ä»·å鿩弹çªï¼ä»
审æ¹éè¿ï¼ |
| | |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate((valid) => { |
| | | if (valid) { |
| | | console.log("productData.value--", productData.value); |
| | | form.value.type = 1; |
| | | form.value.ledgerType = form.value.ledgerType || "åæ²¹"; |
| | | if (form.value.ledgerType === "代å¨") { |
| | | // 代å¨ï¼ååå¨ä½ç½®ï¼æ²¡æäº§åæç»ï¼ååé颿工填 |
| | | if (!form.value.oilDepotId) { |
| | | proxy.$modal.msgWarning("代å¨å¿
é¡»éæ©æ²¹åº"); |
| | | return; |
| | | } |
| | | if (!form.value.tankId) { |
| | | proxy.$modal.msgWarning("代å¨å¿
须鿩å¨ç½"); |
| | | return; |
| | | } |
| | | if (!(Number(form.value.contractAmount) > 0)) { |
| | | proxy.$modal.msgWarning("代å¨å¿
须填åååéé¢"); |
| | | return; |
| | | } |
| | | delete form.value.productData; |
| | | } else { |
| | | // åæ²¹ï¼ååéé¢ç±äº§åæç»æ±æ»ï¼ä»£å¨å段æ¸
空 |
| | | if (productData.value !== null && productData.value.length > 0) { |
| | | form.value.productData = proxy.HaveJson(productData.value); |
| | | } else { |
| | | proxy.$modal.msgWarning("请添å 产åä¿¡æ¯"); |
| | | return; |
| | | } |
| | | form.value.oilDepotId = ""; |
| | | form.value.tankId = ""; |
| | | form.value.contractAmount = null; |
| | | } |
| | | form.value.storageBlobDTOs = fileList; |
| | | form.value.type = 1; |
| | | if (form.value.autoGenerateContractNo) { |
| | | form.value.salesContractNo = ""; |
| | | } |
| | |
| | | background-color: #f4defa; |
| | | } |
| | | |
| | | /* æ¬ç¬ååéé¢è¶
客æ·ä¿¡æåºéï¼åªå 左侧红边ï¼é¿å
è¦çä¸é¢ç交æåºè² */ |
| | | :deep(.trust-fund-exceed) td:first-child { |
| | | box-shadow: inset 3px 0 0 var(--el-color-danger); |
| | | } |
| | | |
| | | .trust-fund-alert { |
| | | margin-top: 6px; |
| | | width: 100%; |
| | | } |
| | | |
| | | .ledger-tabs { |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .ledger-tabs :deep(.el-tabs__header) { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .ledger-tabs :deep(.el-tabs__content) { |
| | | display: none; |
| | | } |
| | | |
| | | .table_list { |
| | | margin-top: unset; |
| | | } |