From 8e70dcadbe5a0fe2526e019607eaf8fcd8f1fc88 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期四, 16 四月 2026 18:00:50 +0800
Subject: [PATCH] 其他金额修改
---
src/views/salesManagement/salesLedger/index.vue | 4636 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 4,088 insertions(+), 548 deletions(-)
diff --git a/src/views/salesManagement/salesLedger/index.vue b/src/views/salesManagement/salesLedger/index.vue
index ce25b37..2b0a984 100644
--- a/src/views/salesManagement/salesLedger/index.vue
+++ b/src/views/salesManagement/salesLedger/index.vue
@@ -1,179 +1,1040 @@
<template>
<div class="app-container">
<div class="search_form">
- <div>
- <span class="search_title">瀹㈡埛鍚嶇О锛�</span>
- <el-input
- v-model="searchForm.customerName"
- style="width: 240px"
- placeholder="璇疯緭鍏�"
- @change="handleQuery"
- clearable
- prefix-icon="Search"
- />
- <el-button type="primary" @click="handleQuery" style="margin-left: 10px">鎼滅储</el-button>
- </div>
- <div>
- <el-button type="primary" @click="openForm('add')">鏂板鍙拌处</el-button>
- <el-button @click="handleOut">瀵煎嚭</el-button>
- <el-button type="danger" plain @click="handleDelete">鍒犻櫎</el-button>
- </div>
+ <el-form :model="searchForm"
+ :inline="true">
+ <el-form-item label="瀹㈡埛鍚嶇О锛�">
+ <el-select v-model="searchForm.customerId"
+ filterable
+ placeholder="璇烽�夋嫨瀹㈡埛鍚嶇О"
+ clearable
+ style="width: 220px"
+ @change="handleQuery">
+ <el-option v-for="item in customerOption"
+ :key="item.id"
+ :label="item.customerName"
+ :value="item.id">
+ {{ item.customerName + "鈥斺��" + item.taxpayerIdentificationNumber }}
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="閿�鍞悎鍚屽彿锛�">
+ <el-input v-model="searchForm.salesContractNo"
+ placeholder="璇疯緭鍏�"
+ clearable
+ prefix-icon="Search"
+ @change="handleQuery" />
+ </el-form-item>
+ <el-form-item label="椤圭洰鍚嶇О锛�">
+ <el-input v-model="searchForm.projectName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ prefix-icon="Search"
+ @change="handleQuery" />
+ </el-form-item>
+ <el-form-item label="褰曞叆鏃ユ湡锛�">
+ <el-date-picker v-model="searchForm.entryDate"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="daterange"
+ placeholder="璇烽�夋嫨"
+ clearable
+ @change="changeDaterange" />
+ </el-form-item>
+ <el-form-item label="鍙戣揣鐘舵�侊細">
+ <el-select v-model="searchForm.deliveryStatus"
+ placeholder="璇烽�夋嫨"
+ clearable
+ style="width: 140px">
+ <el-option label="鏈彂璐�"
+ :value="1" />
+ <el-option label="瀹℃壒涓�"
+ :value="2" />
+ <el-option label="瀹℃壒澶辫触"
+ :value="3" />
+ <el-option label="宸插彂璐�"
+ :value="4" />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="鍏ュ簱鐘舵�侊細">
+ <el-select v-model="searchForm.stockStatus"
+ placeholder="璇烽�夋嫨"
+ clearable
+ style="width: 140px">
+ <el-option label="鏈叆搴�"
+ :value="0" />
+ <el-option label="宸插叆搴�"
+ :value="1" />
+ </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">
- <el-table :data="tableData" border v-loading="tableLoading"
+ <div class="actions">
+ <div>
+ <OtherAmountMaintenanceButton />
+ <ProcessFlowMaintenanceButton />
+ </div>
+ <ProcessFlowConfigSelectDialog v-model:visible="processFlowSelectDialogVisible"
+ :default-route-id="processFlowSelectDefaultRouteId"
+ :bound-route-name="processFlowSelectBoundRouteName"
+ @confirm="handleProcessFlowSelectConfirm" />
+ <el-space wrap>
+ <el-button type="primary"
+ @click="handleSalesStock">鍏ュ簱</el-button>
+ <el-button type="primary"
+ @click="openForm('add')">鏂板鍙拌处</el-button>
+ <el-button type="primary"
+ @click="handleBulkDelivery">鍙戣揣</el-button>
+ <el-button type="primary"
+ plain
+ @click="handleImport">瀵煎叆</el-button>
+ <el-button @click="handleOut">瀵煎嚭</el-button>
+ <el-button type="danger"
+ plain
+ @click="handleDelete">鍒犻櫎</el-button>
+ <el-dropdown @command="handlePrintCommand">
+ <el-button type="primary"
+ plain>
+ 鎵撳嵃鍗曟嵁<el-icon class="el-icon--right">
+ <ArrowDown />
+ </el-icon>
+ </el-button>
+ <template #dropdown>
+ <el-dropdown-menu>
+ <el-dropdown-item command="finishedProcessCard">鐢熶骇娴佺▼鍗★紙鎴愬搧锛�</el-dropdown-item>
+ <el-dropdown-item command="salesOrder">閿�鍞鍗�</el-dropdown-item>
+ <el-dropdown-item command="salesDeliveryNote">閿�鍞彂璐у崟</el-dropdown-item>
+ </el-dropdown-menu>
+ </template>
+ </el-dropdown>
+ <el-button type="primary"
+ plain
+ @click="handlePrintLabel">鎵撳嵃鏍囩</el-button>
+ </el-space>
+ </div>
+ <el-table :data="tableData"
+ border
+ v-loading="tableLoading"
@selection-change="handleSelectionChange"
:expand-row-keys="expandedRowKeys"
- :row-key="row => row.id"
+ :row-key="(row) => row.id"
+ :row-class-name="tableRowClassName"
show-summary
+ style="width: 100%"
:summary-method="summarizeMainTable"
@expand-change="expandChange"
height="calc(100vh - 18.5em)">
- <el-table-column align="center" type="selection" width="55" />
- <el-table-column type="expand">
+ <el-table-column align="center"
+ type="selection"
+ width="55"
+ fixed="left" />
+ <el-table-column type="expand"
+ width="60"
+ fixed="left">
<template #default="props">
- <el-table :data="props.row.children" border
+ <el-table :data="props.row.children"
+ border
show-summary
:summary-method="summarizeChildrenTable">
- <el-table-column align="center" label="搴忓彿" type="index" width="60" />
- <el-table-column label="浜у搧澶х被" prop="productCategory" />
- <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" />
- <el-table-column label="鍗曚綅" prop="unit" />
- <el-table-column label="鏁伴噺" prop="quantity" />
- <el-table-column label="绋庣巼(%)" prop="taxRate" />
- <el-table-column label="鍚◣鍗曚环(鍏�)" prop="taxInclusiveUnitPrice" />
- <el-table-column label="鍚◣鎬讳环(鍏�)" prop="taxInclusiveTotalPrice" />
- <el-table-column label="涓嶅惈绋庢�讳环(鍏�)" prop="taxExclusiveTotalPrice" />
+ <el-table-column align="center"
+ label="搴忓彿"
+ type="index" />
+ <el-table-column label="妤煎眰缂栧彿"
+ prop="floorCode"
+ min-width="100"
+ show-overflow-tooltip />
+ <el-table-column label="浜у搧澶х被"
+ prop="productCategory" />
+ <el-table-column label="瑙勬牸鍨嬪彿"
+ prop="specificationModel" />
+ <el-table-column label="鍘氬害"
+ prop="thickness"
+ min-width="90">
+ <template #default="scope">
+ {{ scope.row.thickness ?? "" }}
+ </template>
+ </el-table-column>
+ <el-table-column label="瀹�(mm)"
+ prop="width"
+ min-width="80">
+ <template #default="scope">
+ {{ scope.row.width ?? "" }}
+ </template>
+ </el-table-column>
+ <el-table-column label="楂�(mm)"
+ prop="height"
+ min-width="80">
+ <template #default="scope">
+ {{ scope.row.height ?? "" }}
+ </template>
+ </el-table-column>
+ <el-table-column label="鍛ㄩ暱(cm)"
+ prop="perimeter"
+ min-width="90">
+ <template #default="scope">
+ {{ scope.row.perimeter ?? "" }}
+ </template>
+ </el-table-column>
+ <el-table-column label="鎬婚潰绉�(m虏)"
+ prop="actualTotalArea"
+ min-width="100">
+ <template #default="scope">
+ {{ scope.row.actualTotalArea ?? "" }}
+ </template>
+ </el-table-column>
+ <el-table-column label="鍔犲伐瑕佹眰"
+ prop="processRequirement"
+ min-width="120"
+ show-overflow-tooltip />
+ <el-table-column label="澶囨敞"
+ prop="remark"
+ min-width="120"
+ show-overflow-tooltip />
+ <el-table-column label="閲嶇"
+ prop="heavyBox"
+ min-width="80">
+ <template #default="scope">
+ {{ scope.row.heavyBox ?? "" }}
+ </template>
+ </el-table-column>
+ <el-table-column label="浜у搧鐘舵��"
+ width="100px"
+ align="center">
+ <template #default="scope">
+ <el-tag v-if="scope.row.approveStatus === 1 && (!scope.row.shippingDate || !scope.row.shippingCarNumber)"
+ type="success">鍏呰冻</el-tag>
+ <el-tag v-else-if="scope.row.approveStatus === 0 && (scope.row.shippingDate || scope.row.shippingCarNumber)"
+ type="success">宸插嚭搴�</el-tag>
+ <el-tag v-else
+ type="danger">涓嶈冻</el-tag>
+ </template>
+ </el-table-column>
+ <!-- <el-table-column label="鍙戣揣鐘舵��" width="140" align="center">
+ <template #default="scope">
+ <el-tag :type="getShippingStatusType(scope.row)" size="small">
+ {{ getShippingStatusText(scope.row) }}
+ </el-tag>
+ </template>
+ </el-table-column> -->
+ <el-table-column label="蹇�掑叕鍙�"
+ prop="expressCompany"
+ show-overflow-tooltip />
+ <el-table-column label="蹇�掑崟鍙�"
+ prop="expressNumber"
+ show-overflow-tooltip />
+ <el-table-column label="鍙戣揣杞︾墝"
+ minWidth="100px"
+ align="center">
+ <template #default="scope">
+ <div>
+ <el-tag type="success"
+ v-if="scope.row.shippingCarNumber">{{ scope.row.shippingCarNumber }}</el-tag>
+ <el-tag v-else
+ type="info">-</el-tag>
+ </div>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍙戣揣鏃ユ湡"
+ minWidth="100px"
+ align="center">
+ <template #default="scope">
+ <div>
+ <div v-if="scope.row.shippingDate">{{ scope.row.shippingDate }}</div>
+ <el-tag v-else
+ type="info">-</el-tag>
+ </div>
+ </template>
+ </el-table-column>
+ <el-table-column label="鏁伴噺"
+ prop="quantity" />
+ <el-table-column label="绋庣巼(%)"
+ prop="taxRate" />
+ <el-table-column label="鍚◣鍗曚环(鍏�)"
+ prop="taxInclusiveUnitPrice"
+ :formatter="formattedNumber" />
+ <el-table-column label="鍚◣鎬讳环(鍏�)"
+ prop="taxInclusiveTotalPrice"
+ :formatter="formattedNumber" />
+ <el-table-column label="涓嶅惈绋庢�讳环(鍏�)"
+ prop="taxExclusiveTotalPrice"
+ :formatter="formattedNumber" />
+ <!--鎿嶄綔-->
+ <!-- <el-table-column Width="60px" label="鎿嶄綔" align="center">
+ <template #default="scope">
+ <el-button
+ link
+ type="primary"
+ :disabled="!canShip(scope.row)"
+ @click="openDeliveryForm(scope.row)">
+ 鍙戣揣
+ </el-button>
+ </template>
+ </el-table-column> -->
</el-table>
</template>
</el-table-column>
- <el-table-column align="center" label="搴忓彿" type="index" width="60" />
- <el-table-column label="閿�鍞悎鍚屽彿" prop="salesContractNo" show-overflow-tooltip/>
- <el-table-column label="瀹㈡埛鍚堝悓鍙�" prop="customerContractNo" show-overflow-tooltip/>
- <el-table-column label="瀹㈡埛鍚嶇О" prop="customerName" show-overflow-tooltip/>
- <el-table-column label="涓氬姟鍛�" prop="salesman" show-overflow-tooltip/>
- <el-table-column label="椤圭洰鍚嶇О" prop="projectName" show-overflow-tooltip/>
- <el-table-column label="鍚堝悓閲戦(鍏�)" prop="contractAmount" show-overflow-tooltip/>
- <el-table-column label="褰曞叆浜�" prop="entryPerson" show-overflow-tooltip/>
- <el-table-column label="褰曞叆鏃ユ湡" prop="entryDate" show-overflow-tooltip/>
- <el-table-column fixed="right" label="鎿嶄綔" min-width="60" align="center">
+ <el-table-column align="center"
+ label="搴忓彿"
+ type="index"
+ width="60" />
+ <el-table-column label="閿�鍞悎鍚屽彿"
+ prop="salesContractNo"
+ width="180"
+ show-overflow-tooltip />
+ <el-table-column label="瀹㈡埛鍚嶇О"
+ prop="customerName"
+ width="300"
+ show-overflow-tooltip />
+ <el-table-column label="涓氬姟鍛�"
+ prop="salesman"
+ width="100"
+ show-overflow-tooltip />
+ <el-table-column label="椤圭洰鍚嶇О"
+ prop="projectName"
+ width="180"
+ show-overflow-tooltip />
+ <el-table-column label="鍚堝悓閲戦(鍏�)"
+ prop="contractAmount"
+ width="220"
+ show-overflow-tooltip
+ :formatter="formattedNumber" />
+ <el-table-column label="鍙戣揣鐘舵��"
+ width="140"
+ align="center">
<template #default="scope">
- <el-button link type="primary" size="small" @click="openForm('edit', scope.row);">缂栬緫</el-button>
+ <el-tag v-if="Number(scope.row.deliveryStatus) === 1"
+ type="info">鏈彂璐�</el-tag>
+ <el-tag v-else-if="Number(scope.row.deliveryStatus) === 2"
+ type="warning">瀹℃壒涓�</el-tag>
+ <el-tag v-else-if="Number(scope.row.deliveryStatus) === 3"
+ type="danger">瀹℃壒涓嶉�氳繃</el-tag>
+ <el-tag v-else-if="Number(scope.row.deliveryStatus) === 4"
+ type="primary">瀹℃壒閫氳繃</el-tag>
+ <el-tag v-else-if="Number(scope.row.deliveryStatus) === 5"
+ type="success">宸插彂璐�</el-tag>
+ <el-tag v-else
+ type="info">-</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍏ュ簱鐘舵��"
+ width="120"
+ align="center">
+ <template #default="scope">
+ <el-tag v-if="Number(scope.row.stockStatus) === 0"
+ type="info">鏈叆搴�</el-tag>
+ <el-tag v-else-if="Number(scope.row.stockStatus) === 1"
+ type="success">宸插叆搴�</el-tag>
+ <el-tag v-else
+ type="info">-</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="褰曞叆浜�"
+ prop="entryPersonName"
+ width="100"
+ show-overflow-tooltip />
+ <el-table-column label="褰曞叆鏃ユ湡"
+ prop="entryDate"
+ width="120"
+ show-overflow-tooltip />
+ <el-table-column label="绛捐鏃ユ湡"
+ prop="executionDate"
+ width="120"
+ show-overflow-tooltip />
+ <el-table-column label="浜や粯鏃ユ湡"
+ prop="deliveryDate"
+ width="120"
+ show-overflow-tooltip />
+ <el-table-column label="澶囨敞"
+ prop="remarks"
+ width="200"
+ show-overflow-tooltip />
+ <el-table-column fixed="right"
+ label="鎿嶄綔"
+ width="200"
+ align="center">
+ <template #default="scope">
+ <el-button link
+ type="primary"
+ @click="openForm('edit', scope.row)"
+ :disabled="!scope.row.isEdit">缂栬緫</el-button>
+ <el-button link
+ type="primary"
+ @click="openProcessFlowSelect(scope.row)"
+ :disabled="!scope.row.isEdit">宸ヨ壓璺嚎</el-button>
+ <el-button link
+ type="primary"
+ @click="downLoadFile(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" />
+ <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="closeDia">
- <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
+ <FormDialog v-model="dialogFormVisible"
+ :title="operationType === 'add' ? '鏂板閿�鍞彴璐﹂〉闈�' : '缂栬緫閿�鍞彴璐﹂〉闈�'"
+ :width="'70%'"
+ :operation-type="operationType"
+ @close="closeDia"
+ @confirm="submitForm"
+ @cancel="closeDia">
+ <el-form :model="form"
+ label-width="140px"
+ label-position="top"
+ :rules="rules"
+ ref="formRef">
+ <!-- 鎶ヤ环鍗曞鍏ュ叆鍙o細鏀惧湪琛ㄥ崟椤堕儴锛岄�夋嫨鍚庡弽鏄惧鎴�/涓氬姟鍛樼瓑 -->
+ <el-row v-if="operationType === 'add'"
+ style="margin-bottom: 10px;">
+ <el-col :span="24"
+ style="text-align: right;">
+ <el-button type="primary"
+ plain
+ @click="openQuotationDialog">
+ 浠庨攢鍞姤浠峰鍏�
+ </el-button>
+ </el-col>
+ </el-row>
<el-row :gutter="30">
<el-col :span="12">
- <el-form-item label="閿�鍞悎鍚屽彿锛�" prop="salesContractNo">
- <el-input v-model="form.salesContractNo" placeholder="鑷姩鐢熸垚" clearable disabled/>
+ <el-form-item label="閿�鍞悎鍚屽彿锛�"
+ prop="salesContractNo">
+ <el-input v-model="form.salesContractNo"
+ placeholder="鑷姩鐢熸垚"
+ clearable
+ disabled />
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="涓氬姟鍛橈細" prop="salesman">
- <el-select v-model="form.salesman" placeholder="璇烽�夋嫨" clearable>
- <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/>
+ <el-form-item label="涓氬姟鍛橈細"
+ prop="salesman">
+ <el-select v-model="form.salesman"
+ placeholder="璇烽�夋嫨"
+ clearable
+ :disabled="operationType === 'view'">
+ <el-option v-for="item in userList"
+ :key="item.nickName"
+ :label="item.nickName"
+ :value="item.nickName" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="30">
<el-col :span="12">
- <el-form-item label="瀹㈡埛鍚堝悓鍙凤細" prop="customerContractNo">
- <el-input v-model="form.customerContractNo" placeholder="璇疯緭鍏�" clearable/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="瀹㈡埛鍚嶇О锛�" prop="customerId">
- <el-select v-model="form.customerId" placeholder="璇烽�夋嫨" clearable>
- <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.id">
- {{item.customerName + '鈥斺��' + item.taxpayerIdentificationNumber}}
+ <el-form-item label="瀹㈡埛鍚嶇О锛�"
+ prop="customerId">
+ <el-select v-model="form.customerId"
+ filterable
+ placeholder="璇烽�夋嫨"
+ clearable
+ :disabled="operationType === 'view'">
+ <el-option v-for="item in customerOption"
+ :key="item.id"
+ :label="item.customerName"
+ :value="item.id">
+ {{
+ item.customerName + "鈥斺��" + item.taxpayerIdentificationNumber
+ }}
</el-option>
</el-select>
</el-form-item>
</el-col>
+ <el-col :span="12">
+ <el-form-item label="椤圭洰鍚嶇О锛�"
+ prop="projectName">
+ <el-input v-model="form.projectName"
+ placeholder="璇疯緭鍏�"
+ clearable
+ :disabled="operationType === 'view'" />
+ </el-form-item>
+ </el-col>
</el-row>
<el-row :gutter="30">
<el-col :span="12">
- <el-form-item label="椤圭洰鍚嶇О锛�" prop="projectName">
- <el-input v-model="form.projectName" placeholder="璇疯緭鍏�" clearable/>
+ <el-form-item label="绛捐鏃ユ湡锛�"
+ prop="executionDate">
+ <el-date-picker style="width: 100%"
+ v-model="form.executionDate"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨"
+ clearable
+ :disabled="operationType === 'view'" />
</el-form-item>
</el-col>
<el-col :span="12">
- <el-form-item label="褰曞叆浜猴細" prop="entryPerson">
- <el-select v-model="form.entryPerson" placeholder="璇烽�夋嫨" clearable>
- <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId"/>
+ <el-form-item label="浜よ揣鏃ユ湡锛�"
+ prop="deliveryDate">
+ <el-date-picker style="width: 100%"
+ v-model="form.deliveryDate"
+ 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="entryPerson">
+ <el-select v-model="form.entryPerson"
+ filterable
+ default-first-option
+ :reserve-keyword="false"
+ placeholder="璇烽�夋嫨"
+ clearable
+ @change="changs">
+ <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="12">
- <el-form-item label="褰曞叆鏃ユ湡锛�" prop="entryDate">
- <el-date-picker
- style="width: 100%"
- v-model="form.entryDate"
- value-format="YYYY-MM-DD"
- format="YYYY-MM-DD"
- type="date"
- placeholder="璇烽�夋嫨"
- clearable
- />
+ <el-form-item label="褰曞叆鏃ユ湡锛�"
+ prop="entryDate">
+ <el-date-picker style="width: 100%"
+ v-model="form.entryDate"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="date"
+ placeholder="璇烽�夋嫨"
+ clearable />
</el-form-item>
</el-col>
</el-row>
<el-row>
- <el-form-item label="浜у搧淇℃伅锛�" prop="entryDate">
- <el-button type="primary" @click="openProductForm('add')">娣诲姞</el-button>
- <el-button plain type="danger" @click="deleteProduct">鍒犻櫎</el-button>
+ <el-form-item label="浜у搧淇℃伅锛�"
+ prop="entryDate">
+ <el-button v-if="operationType !== 'view'"
+ type="primary"
+ :disabled="hasEditingProductRow()"
+ @click="addProductInline">
+ 娣诲姞
+ </el-button>
+ <el-button v-if="operationType !== 'view'"
+ plain
+ type="danger"
+ @click="deleteProduct">鍒犻櫎</el-button>
</el-form-item>
</el-row>
- <el-table :data="productData" border @selection-change="productSelected">
- <el-table-column align="center" type="selection" width="55" />
- <el-table-column align="center" label="搴忓彿" type="index" width="60" />
- <el-table-column label="浜у搧澶х被" prop="productCategory" />
- <el-table-column label="瑙勬牸鍨嬪彿" prop="specificationModel" />
- <el-table-column label="鍗曚綅" prop="unit" />
- <el-table-column label="鏁伴噺" prop="quantity" />
- <el-table-column label="绋庣巼(%)" prop="taxRate" />
- <el-table-column label="鍚◣鍗曚环(鍏�)" prop="taxInclusiveUnitPrice" />
- <el-table-column label="鍚◣鎬讳环(鍏�)" prop="taxInclusiveTotalPrice" />
- <el-table-column label="涓嶅惈绋庢�讳环(鍏�)" prop="taxExclusiveTotalPrice" />
- <el-table-column fixed="right" label="鎿嶄綔" min-width="60" align="center">
+ <el-table :data="productData"
+ border
+ @selection-change="productSelected"
+ show-summary
+ :summary-method="summarizeMainTable">
+ <el-table-column align="center"
+ type="selection"
+ width="55"
+ v-if="operationType !== 'view'"
+ :selectable="(row) => !isProductShipped(row)" />
+ <el-table-column align="center"
+ label="搴忓彿"
+ type="index"
+ width="60" />
+ <el-table-column label="浜у搧澶х被"
+ prop="productCategory"
+ min-width="160">
<template #default="scope">
- <el-button link type="primary" size="small" @click="openProductForm('edit', scope.row);">缂栬緫</el-button>
+ <el-tree-select v-if="scope.row.__editing"
+ v-model="scope.row.__productCategoryId"
+ placeholder="璇烽�夋嫨"
+ clearable
+ filterable
+ check-strictly
+ :data="productOptions"
+ :render-after-expand="false"
+ style="width: 100%"
+ :filter-node-method="filterProductCategoryNode"
+ @change="(val) => handleInlineProductCategoryChange(scope.row, val)" />
+ <span v-else>{{ scope.row.productCategory ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="瑙勬牸鍨嬪彿"
+ prop="specificationModel"
+ min-width="160">
+ <template #default="scope">
+ <el-select v-if="scope.row.__editing"
+ v-model="scope.row.productModelId"
+ placeholder="璇烽�夋嫨"
+ clearable
+ filterable
+ style="width: 100%"
+ @change="(val) => handleInlineProductModelChange(scope.row, val)">
+ <el-option v-for="item in modelOptions"
+ :key="item.id"
+ :label="item.model"
+ :value="item.id" />
+ </el-select>
+ <span v-else>{{ scope.row.specificationModel ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍘氬害(mm)"
+ prop="thickness"
+ min-width="160">
+ <template #default="scope">
+ <el-input-number v-if="scope.row.__editing"
+ v-model="scope.row.thickness"
+ :min="0"
+ :step="0.000000000000001"
+ :precision="15"
+ style="width: 100%"
+ placeholder="璇疯緭鍏�"
+ clearable />
+ <span v-else>{{ scope.row.thickness ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="瀹�(mm)"
+ prop="width"
+ min-width="160">
+ <template #default="scope">
+ <el-input-number v-if="scope.row.__editing"
+ v-model="scope.row.width"
+ :min="0"
+ :step="1"
+ :precision="2"
+ style="width:100%"
+ placeholder="璇疯緭鍏�"
+ clearable
+ @change="() => handleInlineSizeChange(scope.row)"
+ @input="() => handleInlineSizeChange(scope.row)" />
+ <span v-else>{{ scope.row.width ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="楂�(mm)"
+ prop="height"
+ min-width="160">
+ <template #default="scope">
+ <el-input-number v-if="scope.row.__editing"
+ v-model="scope.row.height"
+ :min="0"
+ :step="1"
+ :precision="2"
+ style="width: 100%"
+ placeholder="璇疯緭鍏�"
+ clearable
+ @change="() => handleInlineSizeChange(scope.row)"
+ @input="() => handleInlineSizeChange(scope.row)" />
+ <span v-else>{{ scope.row.height ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="缁撶畻鍗曠墖闈㈢Н(銕�)"
+ prop="settlePieceArea"
+ min-width="160">
+ <template #default="scope">
+ <el-input-number v-if="scope.row.__editing"
+ v-model="scope.row.settlePieceArea"
+ :min="0"
+ :step="0.00001"
+ :precision="5"
+ style="width: 100%"
+ placeholder="璇疯緭鍏�"
+ clearable
+ @change="() => handleInlineSettleAreaChange(scope.row)" />
+ <span v-else>{{ scope.row.settlePieceArea ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鏁伴噺"
+ prop="quantity"
+ min-width="150">
+ <template #default="scope">
+ <el-input-number v-if="scope.row.__editing"
+ v-model="scope.row.quantity"
+ :step="0.1"
+ :min="0"
+ :precision="2"
+ style="width: 100%"
+ placeholder="璇疯緭鍏�"
+ clearable
+ @change="() => handleInlineQuantityChange(scope.row)"
+ @input="() => handleInlineQuantityChange(scope.row)" />
+ <span v-else>{{ scope.row.quantity ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="闈㈢Н(m虏)"
+ prop="actualTotalArea"
+ min-width="160">
+ <template #default="scope">
+ <el-input-number v-if="scope.row.__editing"
+ v-model="scope.row.actualTotalArea"
+ :min="0"
+ :step="0.00001"
+ :precision="5"
+ style="width: 100%"
+ placeholder="鑷姩璁$畻" />
+ <span v-else>{{ scope.row.actualTotalArea ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍚◣鍗曚环(鍏�)"
+ prop="taxInclusiveUnitPrice"
+ min-width="140">
+ <template #default="scope">
+ <el-input-number v-if="scope.row.__editing"
+ :step="0.01"
+ :min="0"
+ :precision="2"
+ style="width: 100%"
+ v-model="scope.row.taxInclusiveUnitPrice"
+ placeholder="璇疯緭鍏�"
+ clearable
+ @change="() => handleInlineUnitPriceChange(scope.row)"
+ @input="() => handleInlineUnitPriceChange(scope.row)" />
+ <span v-else>{{ formattedNumber(null, null, scope.row.taxInclusiveUnitPrice ?? 0) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="绋庣巼(%)"
+ prop="taxRate"
+ min-width="120">
+ <template #default="scope">
+ <el-select v-if="scope.row.__editing"
+ v-model="scope.row.taxRate"
+ placeholder="璇烽�夋嫨"
+ clearable
+ style="width: 100%"
+ @change="() => handleInlineTaxRateChange(scope.row)">
+ <el-option label="1"
+ value="1" />
+ <el-option label="3"
+ value="3" />
+ <el-option label="6"
+ value="6" />
+ <el-option label="9"
+ value="9" />
+ <el-option label="13"
+ value="13" />
+ </el-select>
+ <span v-else>{{ scope.row.taxRate ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍚◣鎬讳环(鍏�)"
+ prop="taxInclusiveTotalPrice"
+ :formatter="formattedNumber"
+ min-width="120" />
+ <el-table-column label="涓嶅惈绋庢�讳环(鍏�)"
+ prop="taxExclusiveTotalPrice"
+ :formatter="formattedNumber"
+ min-width="120" />
+ <el-table-column label="鍙戠エ绫诲瀷"
+ prop="invoiceType"
+ min-width="120">
+ <template #default="scope">
+ <el-select v-if="scope.row.__editing"
+ v-model="scope.row.invoiceType"
+ placeholder="璇烽�夋嫨"
+ clearable
+ style="width: 100%">
+ <el-option label="澧炴櫘绁�"
+ value="澧炴櫘绁�" />
+ <el-option label="澧炰笓绁�"
+ value="澧炰笓绁�" />
+ </el-select>
+ <span v-else>{{ scope.row.invoiceType ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鍔犲伐瑕佹眰"
+ prop="processRequirement"
+ min-width="160"
+ show-overflow-tooltip>
+ <template #default="scope">
+ <el-input v-if="scope.row.__editing"
+ v-model="scope.row.processRequirement"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 100%" />
+ <span v-else>{{ scope.row.processRequirement ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="澶囨敞"
+ prop="remark"
+ min-width="140"
+ show-overflow-tooltip>
+ <template #default="scope">
+ <el-input v-if="scope.row.__editing"
+ v-model="scope.row.remark"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 100%" />
+ <span v-else>{{ scope.row.remark ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="妤煎眰缂栧彿"
+ prop="floorCode"
+ min-width="140"
+ show-overflow-tooltip>
+ <template #default="scope">
+ <el-input v-if="scope.row.__editing"
+ v-model="scope.row.floorCode"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 100%" />
+ <span v-else>{{ scope.row.floorCode ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="閲嶇"
+ prop="heavyBox"
+ min-width="100">
+ <template #default="scope">
+ <el-input v-if="scope.row.__editing"
+ v-model="scope.row.heavyBox"
+ placeholder="璇疯緭鍏�"
+ clearable
+ style="width: 100%" />
+ <span v-else>{{ scope.row.heavyBox ?? "" }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column fixed="right"
+ label="鎿嶄綔"
+ min-width="220"
+ align="center"
+ v-if="operationType !== 'view'">
+ <template #default="scope">
+ <template v-if="scope.row.__editing">
+ <el-button link
+ type="primary"
+ size="small"
+ @click="saveProductInline(scope.row, scope.$index)">淇濆瓨</el-button>
+ <el-button link
+ type="danger"
+ size="small"
+ @click="cancelProductInline(scope.row, scope.$index)">鍙栨秷</el-button>
+ <el-popover :width="560"
+ trigger="click"
+ :hide-after="0"
+ :visible="scope.row.__otherAmountPopoverVisible"
+ @update:visible="(val) => handleOtherAmountPopoverVisibleChange(scope.row, val)">
+ <template #reference>
+ <el-button link
+ type="primary"
+ size="small"
+ @click="openOtherAmountInline(scope.row)">
+ 棰濆鍔犲伐({{ (scope.row.salesProductProcessList || []).length || 0 }})
+ </el-button>
+ </template>
+ <div style="display:flex; align-items:center; justify-content:space-between; gap: 10px; margin-bottom: 8px;">
+ <div style="font-weight: 600; color:#303133;">
+ 棰濆鍔犲伐
+ </div>
+ <el-button type="primary"
+ plain
+ size="small"
+ @click="startAddOtherAmountForRow(scope.row)">
+ 鏂板
+ </el-button>
+ </div>
+ <div v-if="scope.row.__inlineOtherAmountAdding"
+ style="display:flex; flex-direction:column; gap: 8px; margin-bottom: 10px;"
+ @click.stop>
+ <el-select v-model="scope.row.__inlineOtherAmountAddId"
+ filterable
+ clearable
+ placeholder="璇烽�夋嫨棰濆鍔犲伐椤圭洰"
+ style="width: 100%;">
+ <el-option v-for="item in otherAmountSelectOptions"
+ :key="item.id"
+ :label="item.processName"
+ :value="item.id" />
+ </el-select>
+ <div style="display:flex; justify-content:flex-end; gap: 8px;">
+ <el-button size="small"
+ @click="scope.row.__inlineOtherAmountAdding = false; scope.row.__inlineOtherAmountAddId = null">
+ 鍙栨秷
+ </el-button>
+ <el-button type="primary"
+ size="small"
+ :disabled="scope.row.__inlineOtherAmountAddId === null || scope.row.__inlineOtherAmountAddId === undefined || scope.row.__inlineOtherAmountAddId === ''"
+ @click="confirmAddOtherAmountForRow(scope.row)">
+ 纭娣诲姞
+ </el-button>
+ </div>
+ </div>
+ <div v-if="Array.isArray(scope.row.salesProductProcessList) && scope.row.salesProductProcessList.length > 0"
+ style="display:flex; flex-wrap:wrap; gap: 8px;">
+ <div v-for="(item, idx) in scope.row.salesProductProcessList"
+ :key="String(item.id) + '_' + idx"
+ style="display:flex; align-items:center; gap: 8px; flex: 0 0 calc(50% - 4px); max-width: calc(50% - 4px);">
+ <el-tag type="info"
+ style="max-width: 170px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
+ {{ item.processName }}
+ </el-tag>
+ <el-input-number v-model="item.quantity"
+ :min="0"
+ :step="1"
+ :precision="0"
+ style="width: 120px;"
+ placeholder="鏁伴噺"
+ :disabled="operationType === 'view'"
+ @change="handleOtherAmountQuantityChange(scope.row)" />
+ <el-button type="danger"
+ link
+ size="small"
+ @click="removeOtherAmountAtForRow(scope.row, idx)">
+ 鍒犻櫎
+ </el-button>
+ </div>
+ </div>
+ <div v-else
+ style="color:#909399; font-size: 13px;">
+ 鏆傛棤棰濆鍔犲伐
+ </div>
+ </el-popover>
+ </template>
+ <template v-else>
+ <el-button link
+ type="primary"
+ size="small"
+ :disabled="isProductShipped(scope.row)"
+ @click="editProductInline(scope.row, scope.$index)">
+ 缂栬緫
+ </el-button>
+ <el-popover :width="560"
+ trigger="click"
+ :hide-after="0"
+ :visible="scope.row.__otherAmountPopoverVisible"
+ @update:visible="(val) => handleOtherAmountPopoverVisibleChange(scope.row, val)">
+ <template #reference>
+ <el-button link
+ type="primary"
+ size="small"
+ :disabled="isProductShipped(scope.row)"
+ @click="openOtherAmountInline(scope.row)">
+ 棰濆鍔犲伐({{ (scope.row.salesProductProcessList || []).length || 0 }})
+ </el-button>
+ </template>
+ <div style="display:flex; align-items:center; justify-content:space-between; gap: 10px; margin-bottom: 8px;">
+ <div style="font-weight: 600; color:#303133;">
+ 棰濆鍔犲伐
+ </div>
+ <el-button type="primary"
+ plain
+ size="small"
+ :disabled="isProductShipped(scope.row)"
+ @click="startAddOtherAmountForRow(scope.row)">
+ 鏂板
+ </el-button>
+ </div>
+ <div v-if="scope.row.__inlineOtherAmountAdding"
+ style="display:flex; flex-direction:column; gap: 8px; margin-bottom: 10px;"
+ @click.stop>
+ <el-select v-model="scope.row.__inlineOtherAmountAddId"
+ filterable
+ clearable
+ placeholder="璇烽�夋嫨棰濆鍔犲伐椤圭洰"
+ style="width: 100%;"
+ :disabled="isProductShipped(scope.row)">
+ <el-option v-for="item in otherAmountSelectOptions"
+ :key="item.id"
+ :label="item.processName"
+ :value="item.id" />
+ </el-select>
+ <div style="display:flex; justify-content:flex-end; gap: 8px;">
+ <el-button size="small"
+ :disabled="isProductShipped(scope.row)"
+ @click="scope.row.__inlineOtherAmountAdding = false; scope.row.__inlineOtherAmountAddId = null">
+ 鍙栨秷
+ </el-button>
+ <el-button type="primary"
+ size="small"
+ :disabled="isProductShipped(scope.row) || scope.row.__inlineOtherAmountAddId === null || scope.row.__inlineOtherAmountAddId === undefined || scope.row.__inlineOtherAmountAddId === ''"
+ @click="confirmAddOtherAmountForRow(scope.row)">
+ 纭娣诲姞
+ </el-button>
+ </div>
+ </div>
+ <div v-if="Array.isArray(scope.row.salesProductProcessList) && scope.row.salesProductProcessList.length > 0"
+ style="display:flex; flex-wrap:wrap; gap: 8px;">
+ <div v-for="(item, idx) in scope.row.salesProductProcessList"
+ :key="String(item.id) + '_' + idx"
+ style="display:flex; align-items:center; gap: 8px; flex: 0 0 calc(50% - 4px); max-width: calc(50% - 4px);">
+ <el-tag type="info"
+ style="max-width: 170px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
+ {{ item.processName }}
+ </el-tag>
+ <el-input-number v-model="item.quantity"
+ :min="0"
+ :step="1"
+ :precision="0"
+ style="width: 120px;"
+ placeholder="鏁伴噺"
+ :disabled="operationType === 'view' || isProductShipped(scope.row)"
+ @change="handleOtherAmountQuantityChange(scope.row)" />
+ <el-button type="danger"
+ link
+ size="small"
+ :disabled="isProductShipped(scope.row)"
+ @click="removeOtherAmountAtForRow(scope.row, idx)">
+ 鍒犻櫎
+ </el-button>
+ </div>
+ </div>
+ <div v-else
+ style="color:#909399; font-size: 13px;">
+ 鏆傛棤棰濆鍔犲伐
+ </div>
+ </el-popover>
+ </template>
</template>
</el-table-column>
</el-table>
<el-row :gutter="30">
<el-col :span="24">
- <el-form-item label="澶囨敞路锛�" prop="remark">
- <el-input v-model="form.remark" placeholder="璇疯緭鍏�" clearable type="textarea" :rows="2"/>
+ <el-form-item label="澶囨敞锛�"
+ prop="remarks">
+ <el-input v-model="form.remarks"
+ placeholder="璇疯緭鍏�"
+ clearable
+ type="textarea"
+ :rows="2"
+ :disabled="operationType === 'view'" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="30">
<el-col :span="24">
- <el-form-item label="闄勪欢鏉愭枡锛�" prop="remark">
- <el-upload
- v-model:file-list="fileList"
- :action="upload.url"
- multiple
- ref="fileUpload"
- auto-upload
- :headers="upload.headers"
- :before-upload="handleBeforeUpload"
- :on-error="handleUploadError"
- :on-success="handleUploadSuccess"
- :on-remove="handleRemove"
- >
- <el-button type="primary">涓婁紶</el-button>
- <template #tip>
+ <el-form-item label="瀹㈡埛澶囨敞锛�"
+ prop="customerRemarks">
+ <el-input v-model="form.customerRemarks"
+ placeholder="璇疯緭鍏�"
+ clearable
+ type="textarea"
+ :rows="2"
+ :disabled="operationType === 'view'" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="24">
+ <el-form-item label="闄勪欢鏉愭枡锛�"
+ prop="salesLedgerFiles">
+ <el-upload v-model:file-list="fileList"
+ :action="upload.url"
+ multiple
+ ref="fileUpload"
+ auto-upload
+ :headers="upload.headers"
+ :before-upload="handleBeforeUpload"
+ :on-error="handleUploadError"
+ :on-success="handleUploadSuccess"
+ :on-remove="handleRemove">
+ <el-button type="primary"
+ v-if="operationType !== 'view'">涓婁紶</el-button>
+ <template #tip
+ v-if="operationType !== 'view'">
<div class="el-upload__tip">
- 鏂囦欢鏍煎紡鏀寔 doc锛宒ocx锛寈ls锛寈lsx锛宲pt锛宲ptx锛宲df锛宼xt锛寈ml锛宩pg锛宩peg锛宲ng锛実if锛宐mp锛宺ar锛寊ip锛�7z
+ 鏂囦欢鏍煎紡鏀寔
+ doc锛宒ocx锛寈ls锛寈lsx锛宲pt锛宲ptx锛宲df锛宼xt锛寈ml锛宩pg锛宩peg锛宲ng锛実if锛宐mp锛宺ar锛寊ip锛�7z
</div>
</template>
</el-upload>
@@ -181,88 +1042,570 @@
</el-col>
</el-row>
</el-form>
+ </FormDialog>
+ <!-- 浠庢姤浠峰崟瀵煎叆锛堜粎瀹℃壒閫氳繃锛� -->
+ <el-dialog v-model="quotationDialogVisible"
+ title="閫夋嫨瀹℃壒閫氳繃鐨勯攢鍞姤浠峰崟"
+ width="80%"
+ :close-on-click-modal="false">
+ <div style="margin-bottom: 12px; display:flex; gap: 12px; align-items:center;">
+ <el-input v-model="quotationSearchForm.quotationNo"
+ placeholder="璇疯緭鍏ユ姤浠峰崟鍙�"
+ clearable
+ style="max-width: 260px;"
+ @change="fetchQuotationList" />
+ <el-input v-model="quotationSearchForm.customer"
+ placeholder="璇疯緭鍏ュ鎴峰悕绉�"
+ clearable
+ style="max-width: 260px;"
+ @change="fetchQuotationList" />
+ <el-button type="primary"
+ @click="fetchQuotationList">鎼滅储</el-button>
+ <el-button @click="resetQuotationSearch">閲嶇疆</el-button>
+ </div>
+ <el-table :data="quotationList"
+ border
+ stripe
+ v-loading="quotationLoading"
+ height="420px">
+ <el-table-column align="center"
+ label="搴忓彿"
+ type="index"
+ width="60" />
+ <el-table-column prop="quotationNo"
+ label="鎶ヤ环鍗曞彿"
+ width="180"
+ show-overflow-tooltip />
+ <el-table-column prop="customer"
+ label="瀹㈡埛鍚嶇О"
+ min-width="220"
+ show-overflow-tooltip />
+ <el-table-column prop="salesperson"
+ label="涓氬姟鍛�"
+ width="120"
+ show-overflow-tooltip />
+ <el-table-column prop="quotationDate"
+ label="鎶ヤ环鏃ユ湡"
+ width="140" />
+ <el-table-column prop="status"
+ label="瀹℃壒鐘舵��"
+ width="120"
+ align="center" />
+ <el-table-column prop="totalAmount"
+ label="鎶ヤ环閲戦(鍏�)"
+ width="160"
+ align="right">
+ <template #default="scope">
+ {{ Number(scope.row.totalAmount ?? 0).toFixed(2) }}
+ </template>
+ </el-table-column>
+ <el-table-column fixed="right"
+ label="鎿嶄綔"
+ width="120"
+ align="center">
+ <template #default="scope">
+ <el-button type="primary"
+ link
+ @click="applyQuotation(scope.row)">閫夋嫨</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <pagination v-show="quotationPage.total > 0"
+ :total="quotationPage.total"
+ layout="total, sizes, prev, pager, next, jumper"
+ :page="quotationPage.current"
+ :limit="quotationPage.size"
+ @pagination="quotationPaginationChange" />
<template #footer>
- <div class="dialog-footer">
- <el-button type="primary" @click="submitForm">纭</el-button>
- <el-button @click="closeDia">鍙栨秷</el-button>
- </div>
+ <el-button @click="quotationDialogVisible = false">鍏抽棴</el-button>
</template>
</el-dialog>
- <el-dialog v-model="productFormVisible" :title="productOperationType === 'add' ? '鏂板浜у搧' : '缂栬緫浜у搧'" width="40%" @close="closeProductDia">
- <el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef">
+ <FormDialog v-model="productFormVisible"
+ :title="productOperationType === 'add' ? '鏂板浜у搧' : '缂栬緫浜у搧'"
+ :width="'60%'"
+ :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="productCategory">
- <el-select v-model="productForm.productCategory" placeholder="璇烽�夋嫨" clearable>
- <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/>
+ <el-col :span="8">
+ <el-form-item label="浜у搧澶х被锛�"
+ prop="productCategory">
+ <el-tree-select v-model="productForm.productCategory"
+ placeholder="璇烽�夋嫨"
+ clearable
+ filterable
+ :filter-node-method="filterProductCategoryNode"
+ check-strictly
+ @change="getModels"
+ :data="productOptions"
+ :render-after-expand="false"
+ style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <el-form-item label="瑙勬牸鍨嬪彿锛�"
+ prop="productModelId">
+ <el-select v-model="productForm.productModelId"
+ placeholder="璇烽�夋嫨"
+ clearable
+ @change="getProductModel"
+ 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-col>
+ <el-col :span="8">
+ <el-form-item label="鍘氬害锛�"
+ prop="thickness">
+ <el-input-number v-model="productForm.thickness"
+ :min="0"
+ :step="0.000000000000001"
+ :precision="15"
+ style="width: 100%;"
+ placeholder="璇疯緭鍏�"
+ clearable />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <!-- 姣忚涓変釜锛氱◣鐜�/鍚◣鍗曚环/鏁伴噺 -->
+ <el-row :gutter="30">
+ <el-col :span="8">
+ <el-form-item label="鍚◣鍗曚环(鍏�)锛�"
+ prop="taxInclusiveUnitPrice">
+ <el-input-number :step="0.01"
+ :min="0"
+ v-model="productForm.taxInclusiveUnitPrice"
+ style="width: 100%"
+ :precision="2"
+ placeholder="璇疯緭鍏�"
+ clearable
+ @change="calculateFromUnitPrice" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <el-form-item label="绋庣巼(%)锛�"
+ prop="taxRate">
+ <el-select v-model="productForm.taxRate"
+ placeholder="璇烽�夋嫨"
+ clearable
+ @change="calculateFromTaxRate"
+ style="width: 100%">
+ <el-option label="1"
+ value="1" />
+ <el-option label="3"
+ value="3" />
+ <el-option label="6"
+ value="6" />
+ <el-option label="9"
+ value="9" />
+ <el-option label="13"
+ value="13" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <el-form-item label="鏁伴噺锛�"
+ prop="quantity">
+ <el-input-number :step="0.1"
+ :min="0"
+ v-model="productForm.quantity"
+ placeholder="璇疯緭鍏�"
+ clearable
+ :precision="2"
+ @change="() => { calculateFromQuantity(); recalcAreaTotals(); }"
+ style="width: 100%" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <!-- 姣忚涓変釜锛氬惈绋庢�讳环/涓嶅惈绋庢�讳环/鍙戠エ绫诲瀷 -->
+ <el-row :gutter="30">
+ <el-col :span="8">
+ <el-form-item label="鍚◣鎬讳环(鍏�)锛�"
+ prop="taxInclusiveTotalPrice">
+ <el-input v-model="productForm.taxInclusiveTotalPrice"
+ placeholder="璇疯緭鍏�"
+ clearable
+ @change="calculateFromTotalPrice" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <el-form-item label="涓嶅惈绋庢�讳环(鍏�)锛�"
+ prop="taxExclusiveTotalPrice">
+ <el-input v-model="productForm.taxExclusiveTotalPrice"
+ placeholder="璇疯緭鍏�"
+ clearable
+ @change="calculateFromExclusiveTotalPrice" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <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-row>
+ <!-- 姣忚涓変釜锛氬/楂�/瀹為檯鍗曠墖闈㈢Н -->
+ <el-row :gutter="30">
+ <el-col :span="8">
+ <el-form-item label="瀹�(mm)锛�"
+ prop="width">
+ <el-input-number v-model="productForm.width"
+ :min="0"
+ :step="1"
+ :precision="2"
+ style="width: 100%"
+ placeholder="璇疯緭鍏ュ(mm)"
+ clearable
+ @change="recalcAreaFromWidthHeight" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <el-form-item label="楂�(mm)锛�"
+ prop="height">
+ <el-input-number v-model="productForm.height"
+ :min="0"
+ :step="1"
+ :precision="2"
+ style="width: 100%"
+ placeholder="璇疯緭鍏ラ珮(mm)"
+ clearable
+ @change="recalcAreaFromWidthHeight" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <el-form-item label="鍛ㄩ暱(cm)锛�"
+ prop="perimeter">
+ <el-input-number v-model="productForm.perimeter"
+ :min="0"
+ :step="0.01"
+ :precision="2"
+ style="width: 100%"
+ placeholder="璇疯緭鍏�"
+ clearable
+ :disabled="true" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <!-- 姣忚涓変釜锛氬疄闄呭崟鐗囬潰绉�/瀹為檯鎬婚潰绉�/缁撶畻鍗曠墖闈㈢Н -->
+ <el-row :gutter="30">
+ <el-col :span="8">
+ <el-form-item label="瀹為檯鍗曠墖闈㈢Н(銕�)锛�"
+ prop="actualPieceArea">
+ <el-input-number v-model="productForm.actualPieceArea"
+ :min="0"
+ :step="0.00001"
+ :precision="5"
+ style="width: 100%"
+ placeholder="璇疯緭鍏�"
+ clearable
+ @change="recalcAreaTotals" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <el-form-item label="瀹為檯鎬婚潰绉�(銕�)锛�"
+ prop="actualTotalArea">
+ <el-input-number v-model="productForm.actualTotalArea"
+ :min="0"
+ :step="0.00001"
+ :precision="5"
+ style="width: 100%"
+ placeholder="璇疯緭鍏�"
+ clearable />
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <el-form-item label="缁撶畻鍗曠墖闈㈢Н(銕�)锛�"
+ prop="settlePieceArea">
+ <el-input-number v-model="productForm.settlePieceArea"
+ :min="0"
+ :step="0.00001"
+ :precision="5"
+ style="width: 100%"
+ placeholder="璇疯緭鍏�"
+ clearable
+ @change="() => { recalcAreaTotals(); calculateFromUnitPrice(true); }" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <el-form-item label="缁撶畻鎬婚潰绉�(銕�)锛�"
+ prop="settleTotalArea">
+ <el-input-number v-model="productForm.settleTotalArea"
+ :min="0"
+ :step="0.00001"
+ :precision="5"
+ style="width: 100%"
+ placeholder="璇疯緭鍏�"
+ clearable />
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <el-form-item label="缁撶畻鎬婚潰绉�(銕�)锛�"
+ prop="settleTotalArea">
+ <el-input-number v-model="productForm.settleTotalArea"
+ :min="0"
+ :step="0.00001"
+ :precision="5"
+ style="width: 100%"
+ placeholder="璇疯緭鍏�"
+ clearable />
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <el-form-item label="閲嶇锛�"
+ prop="heavyBox">
+ <el-input v-model="productForm.heavyBox"
+ placeholder="璇疯緭鍏�"
+ clearable
+ @change="calculateFromExclusiveTotalPrice" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="30">
<el-col :span="24">
- <el-form-item label="瑙勬牸鍨嬪彿锛�" prop="specificationModel">
- <el-select v-model="productForm.specificationModel" placeholder="璇烽�夋嫨" clearable>
- <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/>
+ <el-form-item label="妤煎眰缂栧彿锛�"
+ prop="floorCode">
+ <el-input v-model="productForm.floorCode"
+ placeholder="璇疯緭鍏ユゼ灞傜紪鍙�"
+ clearable
+ type="textarea"
+ :rows="2"
+ :disabled="operationType === 'view'" />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <!-- 鍏朵粬閲戦锛堝崰婊′竴琛岋細绛夊悓浜� 3 鍒楃綉鏍肩殑鏁磋锛� -->
+ <el-row :gutter="30">
+ <el-col :span="12">
+ <el-form-item label="鍔犲伐瑕佹眰锛�"
+ prop="processRequirement">
+ <el-input v-model="productForm.processRequirement"
+ placeholder="璇疯緭鍏ュ姞宸ヨ姹�"
+ clearable />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="澶囨敞锛�"
+ prop="remark">
+ <el-input v-model="productForm.remark"
+ placeholder="璇疯緭鍏ュ娉�"
+ clearable />
+ </el-form-item>
+ </el-col>
+ </el-row>
+ <el-row :gutter="30">
+ <el-col :span="24">
+ <el-form-item>
+ <template #label>
+ <div style="display:flex; align-items:center; gap: 12px; width: 100%;">
+ <div style="font-weight: 600; color: #303133;">鍏朵粬閲戦锛�</div>
+ <div style="color:#909399; font-size: 13px; flex: 1;">
+ 宸查�夋嫨 {{ productForm?.salesProductProcessList?.length || 0 }} 椤�
+ </div>
+ <el-button v-if="operationType !== 'view'"
+ type="primary"
+ plain
+ size="small"
+ @click="startAddOtherAmount">
+ 鏂板
+ </el-button>
+ </div>
+ </template>
+ <div style="display:flex; flex-direction:column; gap: 12px;">
+ <div v-if="Array.isArray(productForm?.salesProductProcessList) && productForm.salesProductProcessList.length > 0"
+ style="display:flex; flex-wrap:wrap; gap: 12px; align-items:flex-start;">
+ <div v-for="(item, index) in productForm.salesProductProcessList"
+ :key="String(item.id) + '_' + index"
+ style="display:flex; gap: 10px; align-items:center; padding: 10px 12px; border: 1px solid #ebeef5; border-radius: 8px; box-sizing:border-box; min-width: 0;"
+ :style="getOtherAmountCardFlexStyle()">
+ <div style="flex: 1; min-width: 0;">
+ <el-tag type="info"
+ style="width: 100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
+ {{ item.processName }}
+ </el-tag>
+ </div>
+ <div style="flex: 1;">
+ <el-input-number v-model="item.quantity"
+ :min="0"
+ :step="1"
+ :precision="0"
+ style="width: 100%;"
+ placeholder="璇疯緭鍏ユ暟閲�"
+ :disabled="operationType === 'view'"
+ @change="calculateFromUnitPrice(true)" />
+ </div>
+ <el-button v-if="operationType !== 'view'"
+ type="danger"
+ link
+ size="small"
+ @click="removeOtherAmountAt(index)">
+ 鍒犻櫎
+ </el-button>
+ </div>
+ </div>
+ <div v-else
+ style="color:#909399; font-size: 13px;">
+ 鏆傛棤鍏朵粬閲戦
+ </div>
+ </div>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ </FormDialog>
+ <!-- 鍏朵粬閲戦锛氭柊澧炲脊妗� -->
+ <el-dialog v-model="otherAmountAddDialogVisible"
+ title="鏂板鍏朵粬閲戦"
+ width="520px"
+ :close-on-click-modal="false">
+ <div style="padding: 4px 0 10px;">
+ <div style="font-size: 14px; color: #606266; margin-bottom: 10px;">
+ 璇烽�夋嫨瑕佹柊澧炵殑鍏朵粬閲戦椤圭洰
+ </div>
+ <el-select v-model="otherAmountAddId"
+ filterable
+ clearable
+ placeholder="璇烽�夋嫨鍏朵粬閲戦椤圭洰"
+ style="width: 100%;"
+ :disabled="operationType === 'view'">
+ <el-option v-for="item in otherAmountSelectOptions"
+ :key="item.id"
+ :label="item.processName"
+ :value="item.id" />
+ </el-select>
+ </div>
+ <template #footer>
+ <el-button @click="cancelAddOtherAmount">鍙栨秷</el-button>
+ <el-button type="primary"
+ @click="confirmAddOtherAmount"
+ :disabled="operationType === 'view' || otherAmountAddId === null || otherAmountAddId === undefined || otherAmountAddId === ''">
+ 纭娣诲姞
+ </el-button>
+ </template>
+ </el-dialog>
+ <!-- 瀵煎叆寮圭獥 -->
+ <FormDialog v-model="importUpload.open"
+ :title="importUpload.title"
+ :width="'600px'"
+ @close="importUpload.open = false"
+ @confirm="submitImportFile"
+ @cancel="importUpload.open = false">
+ <el-upload ref="importUploadRef"
+ :limit="1"
+ accept=".xlsx,.xls"
+ :action="importUpload.url"
+ :headers="importUpload.headers"
+ :before-upload="importUpload.beforeUpload"
+ :on-success="importUpload.onSuccess"
+ :on-error="importUpload.onError"
+ :on-progress="importUpload.onProgress"
+ :on-change="importUpload.onChange"
+ :auto-upload="false"
+ drag>
+ <i class="el-icon-upload"></i>
+ <div class="el-upload__text">
+ 灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em>
+ </div>
+ <template #tip>
+ <div class="el-upload__tip">
+ 浠呮敮鎸� xls/xlsx锛屽ぇ灏忎笉瓒呰繃 10MB銆�
+ <el-button link
+ type="primary"
+ @click="downloadTemplate">涓嬭浇瀵煎叆妯℃澘</el-button>
+ </div>
+ </template>
+ </el-upload>
+ </FormDialog>
+ <!-- 闄勪欢鍒楄〃寮圭獥 -->
+ <FileListDialog ref="fileListRef"
+ v-model="fileListDialogVisible"
+ title="闄勪欢鍒楄〃" />
+ <!-- 鍙戣揣寮规 -->
+ <el-dialog v-model="deliveryFormVisible"
+ title="鍙戣揣淇℃伅"
+ width="40%"
+ @close="closeDeliveryDia">
+ <el-form :model="deliveryForm"
+ label-width="120px"
+ label-position="top"
+ :rules="deliveryRules"
+ ref="deliveryFormRef">
+ <el-row :gutter="30">
+ <el-col :span="24">
+ <el-form-item label="鍙戣揣绫诲瀷锛�"
+ prop="type">
+ <el-select v-model="deliveryForm.type"
+ 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="unit">
- <el-input v-model="productForm.unit" placeholder="璇疯緭鍏�" clearable/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="鏁伴噺锛�" prop="quantity">
- <el-input v-model="productForm.quantity" placeholder="璇疯緭鍏�" clearable/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="鍚◣鍗曚环(鍏�)锛�" prop="taxInclusiveUnitPrice">
- <el-input v-model="productForm.taxInclusiveUnitPrice" 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>
- <el-option label="1" value="1"/>
- <el-option label="6" value="6"/>
- <el-option label="13" value="13"/>
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="30">
- <el-col :span="12">
- <el-form-item label="鍚◣鎬讳环(鍏�)锛�" prop="taxInclusiveTotalPrice">
- <el-input v-model="productForm.taxInclusiveTotalPrice" placeholder="璇疯緭鍏�" clearable/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="涓嶅惈绋庢�讳环(鍏�)锛�" prop="taxExclusiveTotalPrice">
- <el-input v-model="productForm.taxExclusiveTotalPrice" placeholder="璇疯緭鍏�" clearable/>
- </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>
- <el-option label="澧炴櫘绁�" value="澧炴櫘绁�"/>
- <el-option label="澧炰笓绁�" value="澧炰笓绁�"/>
- </el-select>
+ <!-- 瀹℃壒浜洪�夋嫨锛堜豢鍗忓悓瀹℃壒閲岀殑瀹℃壒浜鸿妭鐐归�夋嫨锛� -->
+ <el-row>
+ <el-col :span="24">
+ <el-form-item>
+ <template #label>
+ <span>瀹℃壒浜洪�夋嫨锛�</span>
+ <el-button type="primary"
+ @click="addApproverNode"
+ style="margin-left: 8px;">鏂板鑺傜偣</el-button>
+ </template>
+ <div style="display: flex; align-items: flex-end; flex-wrap: wrap;">
+ <div v-for="(node, index) in approverNodes"
+ :key="node.id"
+ style="margin-right: 20px; text-align: center; margin-bottom: 10px;">
+ <div>
+ <span>瀹℃壒浜�</span>
+ 鈫�
+ </div>
+ <el-select v-model="node.userId"
+ placeholder="閫夋嫨浜哄憳"
+ filterable
+ style="width: 140px; margin-bottom: 8px;">
+ <el-option v-for="user in userListApprove"
+ :key="user.userId"
+ :label="user.userName"
+ :value="user.userId" />
+ </el-select>
+ <div>
+ <el-button type="danger"
+ @click="removeApproverNode(index)"
+ v-if="approverNodes.length > 1">鍒犻櫎</el-button>
+ </div>
+ </div>
+ </div>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
- <el-button type="primary" @click="submitProduct">纭</el-button>
- <el-button @click="closeProductDia">鍙栨秷</el-button>
+ <el-button type="primary"
+ @click="submitDelivery">纭鍙戣揣</el-button>
+ <el-button @click="closeDeliveryDia">鍙栨秷</el-button>
</div>
</template>
</el-dialog>
@@ -270,401 +1613,2598 @@
</template>
<script setup>
-import { getToken } from "@/utils/auth"
-import pagination from '@/components/PIMTable/Pagination.vue'
-import { ref } from 'vue'
-import {Search} from "@element-plus/icons-vue";
-import {ElMessageBox } from "element-plus";
-import {userListNoPage} from "@/api/system/user.js";
-import {
- ledgerList,
- productList,
- customerList,
- addOrUpdateSalesLedger,
- getSalesLedgerWithProducts, delLedger, addOrUpdateSalesLedgerProduct, delProduct, delLedgerFile
-} from "@/api/salesManagement/salesLedger.js";
-const { proxy } = getCurrentInstance()
-const tableData = ref([])
-const productData = ref([])
-const selectedRows = ref([])
-const productSelectedRows = ref([])
-const userList = ref([])
-const customerOption = ref([])
-const tableLoading = ref(false)
-const page = reactive({
- current: 1,
- size: 10,
-})
-const total = ref(0)
-const fileList = ref([])
+ import { getToken } from "@/utils/auth";
+ import pagination from "@/components/PIMTable/Pagination.vue";
+ import { onMounted, ref, getCurrentInstance, watch, nextTick } from "vue";
+ import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
+ import { ElMessageBox, ElMessage } from "element-plus";
+ import { ArrowDown } from "@element-plus/icons-vue";
+ import useUserStore from "@/store/modules/user";
+ import { approveUserList } from "@/api/collaborativeApproval/approvalProcess.js";
+ import { userListNoPage } from "@/api/system/user.js";
+ import FileListDialog from "@/components/Dialog/FileListDialog.vue";
+ import FormDialog from "@/components/Dialog/FormDialog.vue";
+ import OtherAmountMaintenanceButton from "./components/OtherAmountMaintenanceButton.vue";
+ import ProcessFlowMaintenanceButton from "./components/ProcessFlowMaintenanceButton.vue";
+ import ProcessFlowConfigSelectDialog from "./components/ProcessFlowConfigSelectDialog.vue";
+ import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
+ import {
+ ledgerListPage,
+ productList,
+ customerList,
+ addOrUpdateSalesLedger,
+ getSalesLedgerWithProducts,
+ delLedger,
+ addOrUpdateSalesLedgerProduct,
+ delProduct,
+ delLedgerFile,
+ getProductInventory,
+ salesLedgerProductProcessList,
+ saleProcessBind,
+ getSaleProcessBindInfo,
+ getProcessCard,
+ getSalesOrder,
+ getSalesInvoices,
+ getSalesLabel,
+ salesStock,
+ } from "@/api/salesManagement/salesLedger.js";
+ import { modelList, productTreeList } from "@/api/basicData/product.js";
+ import useFormData from "@/hooks/useFormData.js";
+ import dayjs from "dayjs";
+ import { getCurrentDate } from "@/utils/index.js";
+ import { printFinishedProcessCard } from "./components/processCardPrint.js";
+ import { printSalesOrder } from "./components/salesOrderPrint.js";
+ import { printSalesDeliveryNote } from "./components/salesDeliveryPrint.js";
+ import { printSalesLabel } from "./components/salesLabelPrint.js";
+ // import { salesLedgerProductSetProcessFlowConfig } from "@/api/salesManagement/salesProcessFlowConfig.js";
-// 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
-const operationType = ref('')
-const dialogFormVisible = ref(false)
-const data = reactive({
- searchForm: {
- customerName: '',
- },
- form: {
- salesContractNo: '',
- salesman: '',
- customerContractNo: '',
- customerId: '',
- projectName: '',
- entryPerson: '',
- entryDate: '',
- maintenanceTime: '',
- productData: []
- },
- rules: {
- salesman: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
- customerContractNo: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- customerId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
- projectName: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- entryPerson: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
- entryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
- }
-})
-const { searchForm, form, rules } = toRefs(data)
-// 浜у搧琛ㄥ崟寮规鏁版嵁
-const productFormVisible = ref(false)
-const productOperationType = ref('')
-const currentId = ref('')
-const productFormData = reactive({
- productForm: {
- productCategory: '',
- specificationModel: '',
- unit: '',
- quantity: '',
- taxInclusiveUnitPrice: '',
- taxRate: '',
- taxInclusiveTotalPrice: '',
- taxExclusiveTotalPrice: '',
- invoiceType: '',
- },
- productRules: {
- productCategory: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
- specificationModel: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
- unit: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- quantity: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- taxInclusiveUnitPrice: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- taxRate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
- taxInclusiveTotalPrice: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- taxExclusiveTotalPrice: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
- invoiceType: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
- }
-})
-const { productForm, productRules } = toRefs(productFormData)
-const upload = reactive({
- // 涓婁紶鐨勫湴鍧�
- url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
- // 璁剧疆涓婁紶鐨勮姹傚ご閮�
- headers: { Authorization: "Bearer " + getToken() },
-})
-
-// 鏌ヨ鍒楄〃
-/** 鎼滅储鎸夐挳鎿嶄綔 */
-const handleQuery = () => {
- page.current = 1
- getList()
-}
-const paginationChange = ({ current, limit }) => {
- page.current = current;
- page.size = limit;
- getList()
-}
-const getList = () => {
- tableLoading.value = true
- ledgerList({...searchForm.value, ...page}).then(res => {
- tableLoading.value = false
- tableData.value = res.rows
- tableData.value.map(item => {
- item.children = []
- })
- total.value = res.total
- }).catch(() => {
- tableLoading.value = false
- })
-}
-// 琛ㄦ牸閫夋嫨鏁版嵁
-const handleSelectionChange = (selection) => {
- selectedRows.value = selection
-}
-const productSelected = (selectedRows) => {
- productSelectedRows.value = selectedRows
-}
-const expandedRowKeys = ref([])
-// 灞曞紑琛�
-const expandChange = (row, expandedRows) => {
- if (expandedRows.length > 0) {
- expandedRowKeys.value = []
- try {
- productList({salesLedgerId: row.id, type: 1}).then(res => {
- const index = tableData.value.findIndex(item => item.id === row.id);
- if (index > -1) {
- tableData.value[index].children = res.rows;
- }
- expandedRowKeys.value.push(row.id)
- })
- } catch (error) {
- console.log(error)
- }
- } else {
- expandedRowKeys.value = []
- }
-}
-// 涓昏〃鍚堣鏂规硶
-const summarizeMainTable = (param) => {
- const { columns, data } = param;
- const sums = [];
- columns.forEach((column, index) => {
- if (index === 0) {
- sums[index] = '鍚堣';
- return;
- }
- const prop = column.property;
- if (['contractAmount'].includes(prop)) {
- const values = data.map(item => Number(item[prop]));
- if (!values.every(value => isNaN(value))) {
- sums[index] = values.reduce((acc, val) => (!isNaN(val) ? acc + val : acc), 0);
- } else {
- sums[index] = '';
- }
- } else {
- sums[index] = '';
- }
- })
- return sums;
-};
-// 瀛愯〃鍚堣鏂规硶
-const summarizeChildrenTable = (param) => {
- const { columns, data } = param;
- const sums = [];
- columns.forEach((column, index) => {
- if (index === 0) {
- sums[index] = '鍚堣';
- return;
- }
- const prop = column.property;
- if (['taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice'].includes(prop)) {
- const values = data.map(item => Number(item[prop]));
- if (!values.every(value => isNaN(value))) {
- sums[index] = values.reduce((acc, val) => (!isNaN(val) ? acc + val : acc), 0);
- } else {
- sums[index] = '';
- }
- } else {
- sums[index] = '';
- }
+ const userStore = useUserStore();
+ const { proxy } = getCurrentInstance();
+ const tableData = ref([]);
+ const productData = ref([]);
+ const selectedRows = ref([]);
+ const productSelectedRows = ref([]);
+ const userList = ref([]);
+ const userListApprove = ref([]);
+ const customerOption = ref([]);
+ const productOptions = ref([]);
+ const modelOptions = ref([]);
+ const tableLoading = ref(false);
+ const page = reactive({
+ current: 1,
+ size: 100,
});
- return sums;
-}
-// 鎵撳紑寮规
-const openForm = (type, row) => {
- operationType.value = type
- form.value = {}
- productData.value = []
- userListNoPage().then(res => {
- userList.value = res.data
- })
- customerList().then(res => {
- customerOption.value = res
- })
- if (type === 'edit') {
- currentId.value = row.id;
- getSalesLedgerWithProducts({id: row.id, type: 1}).then(res => {
- form.value = {...res}
- productData.value = form.value.productData
- fileList.value = form.value.salesLedgerFiles
- })
- }
- dialogFormVisible.value = true
-}
-// 涓婁紶鍓嶆牎妫�
-function handleBeforeUpload(file) {
- // 鏍℃鏂囦欢澶у皬
- if (file.size > 1024 * 1024) {
- proxy.$modal.msgError('涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃10MB!')
- return false
- }
- proxy.$modal.loading("姝e湪涓婁紶鏂囦欢锛岃绋嶅��...")
- return true
-}
-// 涓婁紶澶辫触
-function handleUploadError(err) {
- proxy.$modal.msgError("涓婁紶鏂囦欢澶辫触")
- proxy.$modal.closeLoading()
-}
-// 涓婁紶鎴愬姛鍥炶皟
-function handleUploadSuccess(res, file, uploadFiles) {
- proxy.$modal.closeLoading()
- if (res.code === 200) {
- file.tempId = res.data.tempId
- proxy.$modal.msgSuccess("涓婁紶鎴愬姛")
- } else {
- proxy.$modal.msgError(res.msg)
- proxy.$refs.fileUpload.handleRemove(file)
- }
-}
-// 绉婚櫎鏂囦欢
-function handleRemove (file) {
- if (operationType.value === 'edit') {
- let ids = []
- ids.push(file.id)
- delLedgerFile(ids).then(res => {
- proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛")
- })
- }
-}
-// 鎻愪氦琛ㄥ崟
-const submitForm = () => {
- proxy.$refs["formRef"].validate(valid => {
- if (valid) {
- if (productData.value.length > 0) {
- form.value.productData = proxy.HaveJson(productData.value)
+ const total = ref(0);
+ const fileList = ref([]);
+
+ // 宸ヨ壓璺嚎閰嶇疆閫夋嫨寮圭獥锛堢粦瀹氬埌鍙拌处浜у搧锛�
+ const processFlowSelectDialogVisible = ref(false);
+ const processFlowSelectLedgerRow = ref(null);
+ const processFlowSelectDefaultRouteId = ref(null);
+ const processFlowSelectBoundRouteId = ref(null);
+ const processFlowSelectBoundRouteName = ref("");
+
+ // 鐢ㄦ埛淇℃伅琛ㄥ崟寮规鏁版嵁
+ const operationType = ref("");
+ const dialogFormVisible = ref(false);
+ const data = reactive({
+ searchForm: {
+ customerName: "", // 瀹㈡埛鍚嶇О
+ customerId: "", // 瀹㈡埛ID锛堟煡璇笅鎷夛級
+ salesContractNo: "", // 閿�鍞悎鍚岀紪鍙�
+ entryDate: null, // 褰曞叆鏃ユ湡
+ entryDateStart: undefined,
+ entryDateEnd: undefined,
+ deliveryStatus: undefined, // 鍙戣揣鐘舵�侊細1鏈彂璐� 2瀹℃壒涓� 3瀹℃壒澶辫触 4宸插彂璐�
+ stockStatus: undefined, // 鍏ュ簱鐘舵�侊細0鏈叆搴� 1宸插叆搴�
+ },
+ form: {
+ salesContractNo: "",
+ salesman: "",
+ customerId: "",
+ entryPerson: "",
+ entryDate: "",
+ deliveryDate: "",
+ maintenanceTime: "",
+ productData: [],
+ executionDate: "",
+ },
+ rules: {
+ salesman: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ customerId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ entryPerson: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ entryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ deliveryDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ executionDate: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ },
+ });
+ const { form, rules } = toRefs(data);
+ const { form: searchForm } = useFormData(data.searchForm);
+
+ // 鏂板鍙拌处锛氬綍鍏ユ棩鏈熷彉鏇存椂锛屼氦璐ф棩鏈熼粯璁や繚鎸佷负褰曞叆鏃ユ湡鍚庣 7 澶�
+ watch(
+ () => [operationType.value, form.value?.entryDate],
+ () => {
+ if (operationType.value !== "add") return;
+ const ed = form.value?.entryDate;
+ if (!ed) return;
+ form.value.deliveryDate = dayjs(ed).add(7, "day").format("YYYY-MM-DD");
+ }
+ );
+ // 浜у搧琛ㄥ崟寮规鏁版嵁
+ const productFormVisible = ref(false);
+ const productOperationType = ref("");
+ const currentId = ref("");
+ const productFormData = reactive({
+ productForm: {
+ productCategory: "",
+ specificationModel: "",
+ thickness: null,
+ quantity: "",
+ taxInclusiveUnitPrice: "",
+ taxRate: "",
+ taxInclusiveTotalPrice: "",
+ taxExclusiveTotalPrice: "",
+ invoiceType: "",
+ // 鏂板锛氬昂瀵�/闈㈢Н/鍔犲伐涓庡叾浠栭噾棰�
+ width: 0, // 瀹�(mm)
+ height: 0, // 楂�(mm)
+ perimeter: 0, // 鍛ㄩ暱(cm) = (瀹�+楂�)*2锛屽楂樹负 mm
+ // 闈㈢Н瀛楁锛堛帯锛�
+ actualPieceArea: 0, // 瀹為檯鍗曠墖闈㈢Н(銕�)
+ actualTotalArea: 0, // 瀹為檯鎬婚潰绉�(銕�)
+ settlePieceArea: 0, // 缁撶畻鍗曠墖闈㈢Н(銕�)
+ settleTotalArea: 0, // 缁撶畻鎬婚潰绉�(銕�)
+ processRequirement: "", // 鍔犲伐瑕佹眰
+ remark: "", // 澶囨敞
+ salesProductProcessList: [], // 鍏朵粬閲戦锛歔{id, processName, quantity}]
+ processFlowConfigId: null, // 宸ヨ壓娴佺▼閰嶇疆缁戝畾
+ floorCode: "", // 妤煎眰缂栧彿
+ },
+ productRules: {
+ productCategory: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ productModelId: [{ required: true, message: "璇烽�夋嫨", trigger: "change" }],
+ },
+ });
+ const { productForm, productRules } = toRefs(productFormData);
+ // 闃叉寰幆璁$畻鐨勬爣蹇�
+ const isCalculating = ref(false);
+
+ // 浜у搧琛屽唴缂栬緫锛氬彧鍏佽鍚屾椂缂栬緫涓�琛�
+ const editingProductRow = ref(null);
+
+ const ensureProductRowDefaults = row => {
+ if (!row || typeof row !== "object") return;
+ if (!Array.isArray(row.salesProductProcessList))
+ row.salesProductProcessList = [];
+ if (
+ row.__otherAmountPopoverVisible === undefined ||
+ row.__otherAmountPopoverVisible === null
+ )
+ row.__otherAmountPopoverVisible = false;
+ if (
+ row.__inlineOtherAmountAdding === undefined ||
+ row.__inlineOtherAmountAdding === null
+ )
+ row.__inlineOtherAmountAdding = false;
+ if (row.__inlineOtherAmountAddId === undefined)
+ row.__inlineOtherAmountAddId = null;
+ if (row.width === undefined || row.width === null) row.width = 0;
+ if (row.height === undefined || row.height === null) row.height = 0;
+ if (row.perimeter === undefined || row.perimeter === null) row.perimeter = 0;
+ if (row.actualPieceArea === undefined || row.actualPieceArea === null)
+ row.actualPieceArea = 0;
+ if (row.actualTotalArea === undefined || row.actualTotalArea === null)
+ row.actualTotalArea = 0;
+ if (row.settlePieceArea === undefined || row.settlePieceArea === null)
+ row.settlePieceArea = 0;
+ if (row.settleTotalArea === undefined || row.settleTotalArea === null)
+ row.settleTotalArea = 0;
+ if (row.processRequirement === undefined || row.processRequirement === null)
+ row.processRequirement = "";
+ if (row.remark === undefined || row.remark === null) row.remark = "";
+ if (row.floorCode === undefined || row.floorCode === null) row.floorCode = "";
+ if (row.invoiceType === undefined || row.invoiceType === null)
+ row.invoiceType = "";
+ if (row.taxRate === undefined || row.taxRate === null) row.taxRate = "";
+ if (row.quantity === undefined || row.quantity === null) row.quantity = 0;
+ if (
+ row.taxInclusiveUnitPrice === undefined ||
+ row.taxInclusiveUnitPrice === null
+ )
+ row.taxInclusiveUnitPrice = 0;
+ if (
+ row.taxInclusiveTotalPrice === undefined ||
+ row.taxInclusiveTotalPrice === null
+ )
+ row.taxInclusiveTotalPrice = 0;
+ if (
+ row.taxExclusiveTotalPrice === undefined ||
+ row.taxExclusiveTotalPrice === null
+ )
+ row.taxExclusiveTotalPrice = 0;
+ };
+
+ const stopOtherEditingRows = () => {
+ (productData.value || []).forEach(r => {
+ if (r && r.__editing) r.__editing = false;
+ });
+ editingProductRow.value = null;
+ };
+
+ const hasEditingProductRow = () => {
+ return (productData.value || []).some(r => r && r.__editing);
+ };
+
+ const addProductInline = async () => {
+ if (operationType.value === "view") return;
+ if (hasEditingProductRow()) {
+ proxy.$modal.msgWarning("璇峰厛淇濆瓨鎴栧彇娑堝綋鍓嶇紪杈戣");
+ return;
+ }
+ await getProductOptions();
+ await fetchOtherAmountSelectOptions(true);
+ const row = {
+ id: null,
+ __tempKey: `__temp_${Date.now()}_${Math.random().toString(16).slice(2)}`,
+ __editing: true,
+ __isNew: true,
+ __productCategoryId: null,
+ productCategory: "",
+ productModelId: null,
+ specificationModel: "",
+ thickness: null,
+ quantity: 0,
+ taxInclusiveUnitPrice: 0,
+ taxRate: "",
+ taxInclusiveTotalPrice: 0,
+ taxExclusiveTotalPrice: 0,
+ invoiceType: "",
+ width: 0,
+ height: 0,
+ perimeter: 0,
+ actualPieceArea: 0,
+ actualTotalArea: 0,
+ settlePieceArea: 0,
+ settleTotalArea: 0,
+ processRequirement: "",
+ remark: "",
+ salesProductProcessList: [],
+ processFlowConfigId: null,
+ floorCode: "",
+ heavyBox: "",
+ };
+ productData.value.push(row);
+ editingProductRow.value = row;
+ // 璁╃幇鏈夌殑璁$畻/鍏朵粬閲戦閫昏緫澶嶇敤褰撳墠琛�
+ productForm.value = row;
+ };
+
+ const editProductInline = async (row, index) => {
+ if (operationType.value === "view") return;
+ if (!row) return;
+ if (isProductShipped(row)) {
+ proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳界紪杈�");
+ return;
+ }
+ stopOtherEditingRows();
+ await getProductOptions();
+ await fetchOtherAmountSelectOptions(true);
+ ensureProductRowDefaults(row);
+ // 浜у搧澶х被 tree-select 鍥炴樉锛氬悕绉� -> id
+ row.__productCategoryId = findNodeIdByLabel(
+ productOptions.value,
+ row.productCategory
+ );
+
+ // 鍏煎鍚庣瀛楁鍛藉悕锛堜繚鎸佸師閫昏緫锛�
+ row.actualPieceArea = row?.actualPieceArea ?? row?.actual_piece_area ?? 0;
+ row.actualTotalArea = row?.actualTotalArea ?? row?.actual_total_area ?? 0;
+ row.settlePieceArea = row?.settlePieceArea ?? row?.settle_piece_area ?? 0;
+ row.settleTotalArea = row?.settleTotalArea ?? row?.settle_total_area ?? 0;
+ row.processRequirement =
+ row?.processRequirement ?? row?.process_requirement ?? "";
+ row.remark = row?.remark ?? row?.remarks ?? "";
+ row.floorCode = row?.floorCode ?? row?.floor_code ?? "";
+ row.processFlowConfigId =
+ row?.processFlowConfigId ?? row?.process_flow_config_id ?? null;
+ row.perimeter =
+ row?.perimeter ?? row?.heavyBoxPerimeter ?? row?.heavyboxPerimeter ?? 0;
+ row.thickness = row?.thickness;
+
+ row.salesProductProcessList = normalizeOtherAmountsFromRow(row);
+ mergeOtherAmountOptionsBySelection(row.salesProductProcessList);
+ row.salesProductProcessList = fillOtherAmountProcessName(
+ row.salesProductProcessList
+ );
+
+ // 澶囦唤鐢ㄤ簬鍙栨秷
+ row.__backup = JSON.parse(JSON.stringify(row));
+ row.__editing = true;
+ editingProductRow.value = row;
+ productForm.value = row;
+
+ // 鏍规嵁浜у搧澶х被鍚嶇О鍙嶆煡 tree 鑺傜偣 id锛屽苟鍔犺浇瑙勬牸鍨嬪彿鍒楄〃
+ try {
+ const options =
+ productOptions.value && productOptions.value.length > 0
+ ? productOptions.value
+ : await getProductOptions();
+ const categoryId = findNodeIdByLabel(options, row.productCategory);
+ if (categoryId) {
+ const models = await modelList({ id: categoryId });
+ modelOptions.value = models || [];
+ const currentModel = (modelOptions.value || []).find(
+ m => m.model === row.specificationModel
+ );
+ if (currentModel) row.productModelId = currentModel.id;
+ }
+ } catch (e) {
+ console.error("鍔犺浇浜у搧瑙勬牸鍨嬪彿澶辫触", e);
+ }
+
+ // 鍚屾璁$畻涓�娆�
+ recalcPerimeterFromWidthHeight();
+ recalcAreaFromWidthHeight();
+ };
+
+ const validateInlineProductRow = row => {
+ if (!row) return false;
+ if (!row.productCategory) {
+ proxy.$modal.msgWarning("璇烽�夋嫨浜у搧澶х被");
+ return false;
+ }
+ if (!row.productModelId) {
+ proxy.$modal.msgWarning("璇烽�夋嫨瑙勬牸鍨嬪彿");
+ return false;
+ }
+ return true;
+ };
+
+ const saveProductInline = async (row, index) => {
+ if (operationType.value === "view") return;
+ if (!row) return;
+ if (isProductShipped(row)) {
+ proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳界紪杈�");
+ return;
+ }
+ // 纭繚 productForm 鎸囧悜褰撳墠琛岋紝浠ュ鐢ㄨ绠楅�昏緫
+ productForm.value = row;
+ ensureProductRowDefaults(row);
+
+ if (!validateInlineProductRow(row)) return;
+
+ // 鍘氬害绮惧害澶勭悊
+ if (
+ row.thickness !== null &&
+ row.thickness !== undefined &&
+ row.thickness !== ""
+ ) {
+ row.thickness = Number(Number(row.thickness).toFixed(15));
+ }
+
+ // 鎻愪氦鍓嶅厹搴曡绠椾竴娆★紙娌跨敤鍘熼�昏緫锛�
+ recalcAreaTotals();
+ // 鎻愪氦鍏滃簳锛氱◣鐜�/鏁伴噺鏈~鏃舵寜鏁板瓧 0 浼犻��
+ row.taxRate = Number(row.taxRate ?? 0) || 0;
+ row.quantity = Number(row.quantity ?? 0) || 0;
+
+ // 瑙勮寖鍖栧叾浠栭噾棰濇彁浜ょ粨鏋�
+ row.salesProductProcessList = (
+ Array.isArray(row.salesProductProcessList)
+ ? row.salesProductProcessList
+ : []
+ )
+ .map(it => ({
+ id: it?.id,
+ processName: it?.processName ?? "",
+ unitPrice: Number(it?.unitPrice ?? 0) || 0,
+ quantity: Number(it?.quantity ?? 0) || 0,
+ }))
+ .filter(it => it.id !== null && it.id !== undefined && it.id !== "");
+
+ // 瑙勬牸鍨嬪彿锛氭牴鎹� productModelId 鍥炲~鍚嶇О
+ const model = (modelOptions.value || []).find(
+ m => String(m.id) === String(row.productModelId)
+ );
+ if (model?.model) row.specificationModel = model.model;
+
+ if (operationType.value === "edit") {
+ // 鍙拌处宸插瓨鍦細璧板師鎺ュ彛淇濆瓨鍒板悗绔紝鍐嶅洖鎷夊埛鏂�
+ const payload = { ...row, salesLedgerId: currentId.value, type: 1 };
+ delete payload.__backup;
+ delete payload.__editing;
+ delete payload.__isNew;
+ delete payload.__productCategoryId;
+ delete payload.__tempKey;
+ await addOrUpdateSalesLedgerProduct(payload);
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+ await getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then(
+ res => {
+ productData.value = res.productData;
+ }
+ );
+ } else {
+ // 鏂板鍙拌处锛氫粎鍦ㄦ湰鍦� productData 鐢熸晥锛屾渶缁堥殢鍙拌处涓�璧锋彁浜�
+ row.__isNew = false;
+ row.__editing = false;
+ delete row.__backup;
+ }
+
+ stopOtherEditingRows();
+ };
+
+ const cancelProductInline = (row, index) => {
+ if (!row) return;
+ if (row.__isNew) {
+ productData.value.splice(index, 1);
+ } else if (row.__backup) {
+ const restored = JSON.parse(JSON.stringify(row.__backup));
+ // 淇濈暀 id 涓庣姸鎬佸瓧娈�
+ const keepId = row.id;
+ Object.keys(row).forEach(k => delete row[k]);
+ Object.assign(row, restored);
+ row.id = keepId;
+ row.__editing = false;
+ delete row.__backup;
+ }
+ stopOtherEditingRows();
+ };
+
+ const openOtherAmountInline = async row => {
+ if (!row) return;
+ if (operationType.value === "view") return;
+ if (isProductShipped(row)) {
+ proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳界紪杈�");
+ return;
+ }
+ ensureProductRowDefaults(row);
+ productForm.value = row;
+ otherAmountAddTargetRow.value = row;
+ await fetchOtherAmountSelectOptions(true);
+ mergeOtherAmountOptionsBySelection(row.salesProductProcessList);
+ row.salesProductProcessList = fillOtherAmountProcessName(
+ row.salesProductProcessList
+ );
+ // 鍙仛鏁版嵁鍑嗗涓庢墦寮�娴眰锛堟柊澧炵敱娴眰鍐呮寜閽Е鍙戯級
+ row.__otherAmountPopoverVisible = true;
+ };
+
+ const keepOtherAmountPopoverOpenKey = ref(null);
+ const keepOtherAmountPopoverOpenUntil = ref(0);
+
+ const getOtherAmountRowKey = row => String(row?.__tempKey ?? row?.id ?? "");
+
+ const lockOtherAmountPopoverOpen = (row, durationMs = 1200) => {
+ const key = getOtherAmountRowKey(row);
+ if (!key) return;
+ keepOtherAmountPopoverOpenKey.value = key;
+ keepOtherAmountPopoverOpenUntil.value = Date.now() + durationMs;
+ };
+
+ const handleOtherAmountPopoverVisibleChange = (row, visible) => {
+ if (!row) return;
+ if (visible) {
+ row.__otherAmountPopoverVisible = true;
+ return;
+ }
+ if (row.__inlineOtherAmountAdding) {
+ row.__otherAmountPopoverVisible = true;
+ return;
+ }
+ const key = getOtherAmountRowKey(row);
+ const shouldKeepOpen = Boolean(
+ key &&
+ keepOtherAmountPopoverOpenKey.value === key &&
+ Date.now() < keepOtherAmountPopoverOpenUntil.value
+ );
+ row.__otherAmountPopoverVisible = shouldKeepOpen;
+ };
+
+ const startAddOtherAmountForRow = async row => {
+ if (!row) return;
+ if (operationType.value === "view") return;
+ if (isProductShipped(row)) {
+ proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳界紪杈�");
+ return;
+ }
+ ensureProductRowDefaults(row);
+ productForm.value = row;
+ await fetchOtherAmountSelectOptions(true);
+ mergeOtherAmountOptionsBySelection(row.salesProductProcessList);
+ row.salesProductProcessList = fillOtherAmountProcessName(
+ row.salesProductProcessList
+ );
+ row.__inlineOtherAmountAddId = null;
+ row.__inlineOtherAmountAdding = true;
+ row.__otherAmountPopoverVisible = true;
+ };
+
+ const confirmAddOtherAmountForRow = row => {
+ if (!row) return;
+ ensureProductRowDefaults(row);
+ productForm.value = row;
+ const selectedId = row.__inlineOtherAmountAddId;
+ if (selectedId === null || selectedId === undefined || selectedId === "")
+ return;
+ const opt = otherAmountSelectOptions.value.find(
+ o => String(o.id) === String(selectedId)
+ );
+ if (!opt) return;
+ const exists = (row.salesProductProcessList ?? []).some(
+ it => String(it?.id) === String(opt.id)
+ );
+ if (exists) {
+ proxy.$modal.msgWarning("璇ュ叾浠栭噾棰濋」鐩凡娣诲姞");
+ return;
+ }
+ row.salesProductProcessList.push({
+ id: opt.id,
+ processName: opt.processName,
+ unitPrice: opt.unitPrice ?? 0,
+ quantity: 0,
+ });
+ row.__inlineOtherAmountAddId = null;
+ row.__inlineOtherAmountAdding = false;
+ row.__otherAmountPopoverVisible = true;
+ calculateFromUnitPrice(true);
+ };
+
+ const removeOtherAmountAtForRow = (row, index) => {
+ if (!row) return;
+ if (operationType.value === "view") return;
+ if (isProductShipped(row)) return;
+ productForm.value = row;
+ removeOtherAmountAt(index);
+ };
+
+ const handleOtherAmountQuantityChange = row => {
+ if (!row) return;
+ productForm.value = row;
+ calculateFromUnitPrice(true);
+ };
+
+ const handleInlineProductCategoryChange = async (row, val) => {
+ if (!row) return;
+ productForm.value = row;
+ // 澶嶇敤鍘熸湁閫昏緫锛氫細鍐欏叆 productCategory(鍚嶇О)銆侀噸缃鏍�/鍘氬害骞舵媺鍙栧瀷鍙�
+ await getModels(val);
+ // 琛屽唴缂栬緫鏃舵妸閫変腑鐨� id 璁板綍涓嬫潵锛屼究浜庡洖鏄�
+ row.__productCategoryId = val;
+ };
+
+ const handleInlineProductModelChange = (row, val) => {
+ if (!row) return;
+ productForm.value = row;
+ // 澶嶇敤鍘熸湁閫昏緫锛氫細鍐欏叆 specificationModel銆佸帤搴�
+ getProductModel(val);
+ };
+
+ const handleInlineSizeChange = row => {
+ if (!row) return;
+ productForm.value = row;
+ recalcPerimeterFromWidthHeight();
+ recalcAreaFromWidthHeight();
+ recalcAreaTotals();
+ };
+
+ const handleInlineUnitPriceChange = row => {
+ if (!row) return;
+ productForm.value = row;
+ calculateFromUnitPrice();
+ recalcAreaTotals();
+ };
+
+ const handleInlineQuantityChange = row => {
+ if (!row) return;
+ productForm.value = row;
+ calculateFromQuantity();
+ recalcAreaTotals();
+ };
+
+ const handleInlineTaxRateChange = row => {
+ if (!row) return;
+ productForm.value = row;
+ calculateFromTaxRate();
+ };
+
+ const handleInlineSettleAreaChange = row => {
+ if (!row) return;
+ productForm.value = row;
+ recalcAreaTotals();
+ calculateFromUnitPrice(true);
+ };
+ const upload = reactive({
+ // 涓婁紶鐨勫湴鍧�
+ url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
+ // 璁剧疆涓婁紶鐨勮姹傚ご閮�
+ headers: { Authorization: "Bearer " + getToken() },
+ });
+ // 鎶ヤ环鍗曞鍏ョ浉鍏�
+ const quotationDialogVisible = ref(false);
+ const quotationLoading = ref(false);
+ const quotationList = ref([]);
+ const quotationSearchForm = reactive({
+ quotationNo: "",
+ customer: "",
+ });
+ // 鎶ヤ环鍗曞脊妗嗗垎椤�
+ const quotationPage = reactive({
+ current: 1,
+ size: 10,
+ total: 0,
+ });
+ const selectedQuotation = ref(null);
+
+ // 鍙戣揣鐩稿叧
+ const deliveryFormVisible = ref(false);
+ const currentDeliveryRows = ref([]);
+ const deliveryFormData = reactive({
+ deliveryForm: {
+ type: "璐ц溅", // 璐ц溅, 蹇��
+ },
+ deliveryRules: {
+ type: [{ required: true, message: "璇烽�夋嫨鍙戣揣绫诲瀷", trigger: "change" }],
+ },
+ });
+ const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
+
+ // 浜у搧寮规锛氬叾浠栭噾棰濆閫変笅鎷夛紙鍩轰簬鈥滃叾浠栭噾棰濈淮鎶も�濇煡璇㈡帴鍙o級
+ const otherAmountSelectOptions = ref([]); // [{id, processName}]
+ const otherAmountSelectOptionsLoading = ref(false);
+
+ const fetchOtherAmountSelectOptions = async (force = false) => {
+ if (!force && otherAmountSelectOptions.value.length > 0) return;
+ otherAmountSelectOptionsLoading.value = true;
+ try {
+ const params = {
+ current: 1,
+ // 涓嬫媺妗嗗敖閲忎竴娆℃�ф媺鍏紝閬垮厤澶氭鍒嗛〉褰卞搷閫夋嫨浣撻獙
+ size: 1000,
+ };
+ const res = await salesLedgerProductProcessList(params);
+ const records = res?.records ?? res?.data?.records ?? [];
+
+ otherAmountSelectOptions.value = records.map(item => ({
+ id: item.id,
+ processName: item.processName ?? "",
+ unitPrice: item.unitPrice ?? 0,
+ }));
+ } finally {
+ otherAmountSelectOptionsLoading.value = false;
+ }
+ };
+
+ const normalizeOtherAmountsFromRow = row => {
+ if (!row) return [];
+ const raw =
+ row.other_amounts ??
+ row.otherAmounts ??
+ row.otherAmountProjects ??
+ row.otherAmountList ??
+ row.salesProductProcessList ??
+ [];
+
+ if (!Array.isArray(raw)) return [];
+ if (raw.length === 0) return [];
+
+ // 鎯呭喌1锛氬悗绔洿鎺ヨ繑鍥� [{id, processName}...]
+ if (typeof raw[0] === "object") {
+ return raw
+ .map(it => {
+ const id = it?.id ?? it?.processId ?? it?.otherAmountId ?? null;
+ const quantity =
+ Number(
+ it?.quantity ??
+ it?.processQuantity ??
+ it?.otherQuantity ??
+ it?.process_quantity ??
+ it?.other_amount_quantity
+ ) || 0;
+ return {
+ id,
+ processName: it?.processName ?? "",
+ quantity,
+ };
+ })
+ .filter(it => it.id !== null && it.id !== undefined && it.id !== "");
+ }
+
+ // 鎯呭喌2锛氬悗绔彧杩斿洖 ids: [1,2,3]
+ return raw
+ .map(id => ({
+ id,
+ processName: "",
+ quantity: 0,
+ }))
+ .filter(it => it.id !== null && it.id !== undefined && it.id !== "");
+ };
+
+ const mergeOtherAmountOptionsBySelection = selected => {
+ const list = Array.isArray(selected) ? selected : [];
+ for (const s of list) {
+ const exists = otherAmountSelectOptions.value.some(
+ o => String(o.id) === String(s.id)
+ );
+ if (!exists) {
+ otherAmountSelectOptions.value.push({
+ id: s.id,
+ processName: s.processName ?? "",
+ });
+ }
+ }
+ };
+
+ const fillOtherAmountProcessName = selected => {
+ const list = Array.isArray(selected) ? selected : [];
+ return list.map(s => {
+ const opt = otherAmountSelectOptions.value.find(
+ o => String(o.id) === String(s.id)
+ );
+ return {
+ id: s.id,
+ processName: opt?.processName ?? s.processName ?? "",
+ unitPrice: opt?.unitPrice ?? s.unitPrice ?? 0,
+ quantity: Number(s.quantity ?? 0) || 0,
+ };
+ });
+ };
+
+ // 鈥滃叾浠栭噾棰濃�濆崱鐗囧竷灞�锛氬彧鏈変竴鏉℃椂鍗犳弧鏁磋锛�>=2鏃朵袱鍒楁帓甯�
+ const getOtherAmountCardFlexStyle = () => {
+ const list = productForm.value?.salesProductProcessList;
+ const len = Array.isArray(list) ? list.length : 0;
+ if (len === 1) {
+ return { flex: "0 0 100%", maxWidth: "100%", width: "100%" };
+ }
+ return {
+ flex: "0 0 calc(50% - 6px)",
+ maxWidth: "calc(50% - 6px)",
+ width: "calc(50% - 6px)",
+ };
+ };
+
+ // 鍏朵粬閲戦锛氱偣鍑烩�滄柊澧炩�濆悗鍦ㄥ脊绐楅噷閫夋嫨涓�涓」鐩�
+ const otherAmountAddDialogVisible = ref(false);
+ const otherAmountAddId = ref(null);
+ const otherAmountAddTargetRow = ref(null);
+ const otherAmountAddTargetRowKey = ref(null);
+
+ const startAddOtherAmount = () => {
+ if (operationType.value === "view") return;
+ otherAmountAddDialogVisible.value = true;
+ otherAmountAddId.value = null;
+ // 閫氬父 openProductForm 宸茬粡鎷夎繃 options锛岃繖閲屽厹搴�
+ if (otherAmountSelectOptions.value.length === 0) {
+ fetchOtherAmountSelectOptions(true);
+ }
+ };
+
+ const cancelAddOtherAmount = () => {
+ otherAmountAddDialogVisible.value = false;
+ otherAmountAddId.value = null;
+ otherAmountAddTargetRow.value = null;
+ otherAmountAddTargetRowKey.value = null;
+ keepOtherAmountPopoverOpenKey.value = null;
+ keepOtherAmountPopoverOpenUntil.value = 0;
+ };
+
+ const handleOtherAmountSelected = id => {
+ const selectedId = id ?? otherAmountAddId.value;
+ if (selectedId === null || selectedId === undefined || selectedId === "")
+ return;
+ const opt = otherAmountSelectOptions.value.find(
+ o => String(o.id) === String(selectedId)
+ );
+ if (!opt) return;
+
+ const exists = (productForm.value?.salesProductProcessList ?? []).some(
+ it => String(it?.id) === String(opt.id)
+ );
+ if (exists) {
+ proxy.$modal.msgWarning("璇ュ叾浠栭噾棰濋」鐩凡娣诲姞");
+ return;
+ }
+
+ productForm.value.salesProductProcessList.push({
+ id: opt.id,
+ processName: opt.processName,
+ unitPrice: opt.unitPrice ?? 0,
+ quantity: 0,
+ });
+ calculateFromUnitPrice(true);
+
+ // 閫夋嫨瀹屾垚鍚庡叧闂�滄柊澧炲叾浠栭噾棰濃�濆脊绐楋紝骞朵繚鎸佽鍐呪�滃叾浠栭噾棰濃�濆脊灞傚紑鍚紝渚夸簬鐩存帴濉啓鏁伴噺
+ otherAmountAddDialogVisible.value = false;
+ otherAmountAddId.value = null;
+ const reopenOtherAmountPopover = () => {
+ let targetRow = otherAmountAddTargetRow.value;
+ const rowKey = otherAmountAddTargetRowKey.value;
+ if (rowKey) {
+ const matchedRow = (productData.value || []).find(
+ it => String(it?.__tempKey ?? it?.id ?? "") === rowKey
+ );
+ if (matchedRow) targetRow = matchedRow;
+ }
+ if (targetRow && typeof targetRow === "object") {
+ lockOtherAmountPopoverOpen(targetRow, 1500);
+ targetRow.__otherAmountPopoverVisible = true;
+ }
+ };
+ nextTick(() => {
+ reopenOtherAmountPopover();
+ setTimeout(reopenOtherAmountPopover, 0);
+ setTimeout(reopenOtherAmountPopover, 80);
+ });
+ otherAmountAddTargetRow.value = null;
+ otherAmountAddTargetRowKey.value = null;
+ };
+
+ const confirmAddOtherAmount = () => {
+ handleOtherAmountSelected(otherAmountAddId.value);
+ };
+
+ const removeOtherAmountAt = index => {
+ if (operationType.value === "view") return;
+ if (!Array.isArray(productForm.value?.salesProductProcessList)) return;
+ productForm.value.salesProductProcessList.splice(index, 1);
+ calculateFromUnitPrice(true);
+ };
+
+ // 鍙戣揣瀹℃壒浜鸿妭鐐癸紙浠垮崗鍚屽鎵� infoFormDia.vue锛�
+ const approverNodes = ref([{ id: 1, userId: null }]);
+ let nextApproverId = 2;
+ const addApproverNode = () => {
+ approverNodes.value.push({ id: nextApproverId++, userId: null });
+ };
+ const removeApproverNode = index => {
+ approverNodes.value.splice(index, 1);
+ };
+
+ // 瀵煎叆鐩稿叧
+ const importUploadRef = ref(null);
+ const importUpload = reactive({
+ title: "瀵煎叆閿�鍞彴璐�",
+ open: false,
+ url: import.meta.env.VITE_APP_BASE_API + "/sales/ledger/import",
+ headers: { Authorization: "Bearer " + getToken() },
+ isUploading: false,
+ beforeUpload: file => {
+ const isExcel = file.name.endsWith(".xlsx") || file.name.endsWith(".xls");
+ const isLt10M = file.size / 1024 / 1024 < 10;
+ if (!isExcel) {
+ proxy.$modal.msgError("涓婁紶鏂囦欢鍙兘鏄� xlsx/xls 鏍煎紡!");
+ return false;
+ }
+ if (!isLt10M) {
+ proxy.$modal.msgError("涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃 10MB!");
+ return false;
+ }
+ return true;
+ },
+ onChange: (file, fileList) => {
+ console.log("鏂囦欢鐘舵�佹敼鍙�", file, fileList);
+ },
+ onProgress: (event, file, fileList) => {
+ console.log("涓婁紶涓�...", event.percent);
+ },
+ onSuccess: (response, file, fileList) => {
+ console.log("涓婁紶鎴愬姛", response, file, fileList);
+ importUpload.isUploading = false;
+ if (response.code === 200) {
+ proxy.$modal.msgSuccess("瀵煎叆鎴愬姛");
+ importUpload.open = false;
+ if (importUploadRef.value) {
+ importUploadRef.value.clearFiles();
+ }
+ getList();
} else {
- proxy.$modal.msgWarning('璇锋坊鍔犱骇鍝佷俊鎭�')
- return
+ proxy.$modal.msgError(response.msg || "瀵煎叆澶辫触");
}
- let tempFileIds = []
- if (fileList.value.length > 0) {
- tempFileIds = fileList.value.map(item => item.tempId)
+ },
+ onError: (error, file, fileList) => {
+ console.error("涓婁紶澶辫触", error, file, fileList);
+ importUpload.isUploading = false;
+ proxy.$modal.msgError("瀵煎叆澶辫触锛岃閲嶈瘯");
+ },
+ });
+
+ const changeDaterange = value => {
+ if (value) {
+ searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
+ searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
+ } else {
+ searchForm.entryDateStart = undefined;
+ searchForm.entryDateEnd = undefined;
+ }
+ handleQuery();
+ };
+
+ // 鏌ヨ鍒楄〃
+ /** 鎼滅储鎸夐挳鎿嶄綔 */
+ const handleQuery = () => {
+ // 鍙湁鍦ㄧ偣鍑绘悳绱㈡寜閽椂鎵嶉噸缃〉鐮佸埌绗竴椤�
+ // 閬垮厤琛ㄥ崟瀛楁change浜嬩欢骞叉壈鍒嗛〉
+ if (arguments.length === 0) {
+ page.current = 1;
+ }
+ expandedRowKeys.value = [];
+ getList();
+ };
+ const paginationChange = obj => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getList();
+ };
+ const getList = () => {
+ tableLoading.value = true;
+ const { entryDate, ...rest } = searchForm;
+ // 灏嗚寖鍥存棩鏈熷瓧娈典紶閫掔粰鍚庣
+ const params = { ...rest, ...page };
+ // 绉婚櫎褰曞叆鏃ユ湡鐨勯粯璁ゅ�艰缃紝鍙繚鐣欒寖鍥存棩鏈熷瓧娈�
+ delete params.entryDate;
+ // 鏌ヨ瀹㈡埛鍚嶇О涓庢柊澧炰繚鎸佷竴鑷达細鍏堥�� customerId锛屽啀鏄犲皠涓� customerName 鏌ヨ
+ const selectedCustomer = (customerOption.value || []).find(
+ item => String(item?.id ?? "") === String(params.customerId ?? "")
+ );
+ if (selectedCustomer?.customerName) {
+ params.customerName = String(selectedCustomer.customerName).trim();
+ } else {
+ const cn =
+ params.customerName != null ? String(params.customerName).trim() : "";
+ if (cn) {
+ params.customerName = cn;
+ } else {
+ delete params.customerName;
}
- form.value.tempFileIds = tempFileIds
- form.value.type = 1
- addOrUpdateSalesLedger(form.value).then(res => {
- proxy.$modal.msgSuccess("鎻愪氦鎴愬姛")
- closeDia()
- getList()
+ }
+ delete params.customerId;
+ return ledgerListPage(params)
+ .then(res => {
+ tableLoading.value = false;
+ tableData.value = res.records;
+ tableData.value.map(item => {
+ item.children = [];
+ });
+ total.value = res.total;
+ return res;
})
+ .catch(() => {
+ tableLoading.value = false;
+ });
+ };
+
+ // 鍏ュ簱锛堥攢鍞彴璐� -> 鍏ュ簱鐘舵�侊級
+ const handleSalesStock = async () => {
+ if (selectedRows.value.length !== 1) {
+ ElMessage.warning("璇峰嬀閫変竴鏉″彴璐︽暟鎹繘琛屽叆搴�");
+ return;
}
- })
-}
-// 鍏抽棴寮规
-const closeDia = () => {
- proxy.resetForm("formRef")
- dialogFormVisible.value = false
-}
-// 鎵撳紑浜у搧寮规
-const openProductForm = (type, row) => {
- productOperationType.value = type
- productForm.value = {}
- proxy.resetForm("productFormRef")
- if (type === 'edit') {
- productForm.value = {...row}
- }
- productFormVisible.value = true
-}
-// 鎻愪氦浜у搧琛ㄥ崟
-const submitProduct = () => {
- proxy.$refs["productFormRef"].validate(valid => {
- if (valid) {
- if (operationType.value === "edit") {
- submitProductEdit()
- } else {
- productData.value.push({...productForm.value})
- closeProductDia()
+ const row = selectedRows.value[0] || {};
+ const id = row?.id;
+ if (!id) {
+ ElMessage.warning("鎵�閫夋暟鎹己灏慽d锛屾棤娉曞叆搴�");
+ return;
+ }
+ if (Number(row.stockStatus) === 1) {
+ ElMessage.info("璇ュ彴璐﹀凡鍏ュ簱锛屾棤闇�閲嶅鎿嶄綔");
+ return;
+ }
+ try {
+ await ElMessageBox.confirm("纭瀵规墍閫夊彴璐︽墽琛屽叆搴擄紵", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ });
+ } catch {
+ return;
+ }
+ proxy?.$modal?.loading?.("姝e湪鍏ュ簱锛岃绋嶅��...");
+ try {
+ await salesStock({ id });
+ proxy?.$modal?.msgSuccess?.("鍏ュ簱鎴愬姛");
+ await getList();
+ } catch (e) {
+ proxy?.$modal?.msgError?.("鍏ュ簱澶辫触锛岃绋嶅悗閲嶈瘯");
+ } finally {
+ proxy?.$modal?.closeLoading?.();
+ }
+ };
+
+ // 鎵撳紑鈥滃伐鑹鸿矾绾块厤缃�濋�夋嫨寮圭獥锛堝繀椤绘樉寮忛�夋嫨锛�
+ const openProcessFlowSelect = async ledgerRow => {
+ if (!ledgerRow) return;
+ if (!ledgerRow.isEdit) return;
+
+ processFlowSelectLedgerRow.value = ledgerRow;
+ processFlowSelectDefaultRouteId.value = null;
+ processFlowSelectBoundRouteId.value = null;
+ processFlowSelectBoundRouteName.value = "";
+
+ try {
+ const res = await getSaleProcessBindInfo(ledgerRow.id);
+ const info = res?.data ?? res ?? {};
+ const boundId = info?.processRouteId ?? info?.routeId ?? info?.id ?? null;
+ const boundName =
+ info?.processRouteName ?? info?.routeName ?? info?.name ?? "";
+ processFlowSelectBoundRouteId.value = boundId;
+ processFlowSelectBoundRouteName.value = boundName;
+ processFlowSelectDefaultRouteId.value = boundId;
+ } catch (e) {
+ // 鏌ヨ澶辫触鏃舵寜鏈粦瀹氬鐞嗭紝涓嶉樆濉炲脊绐�
+ processFlowSelectBoundRouteId.value = null;
+ processFlowSelectBoundRouteName.value = "";
+ processFlowSelectDefaultRouteId.value = null;
+ }
+
+ processFlowSelectDialogVisible.value = true;
+ };
+
+ // 缁戝畾宸ヨ壓璺嚎鍒板綋鍓嶅彴璐︽暟鎹�
+ const handleProcessFlowSelectConfirm = async routeId => {
+ const ledgerRow = processFlowSelectLedgerRow.value;
+ if (!ledgerRow?.id) return;
+
+ const finalRouteId = routeId ?? null;
+ if (!finalRouteId) return;
+
+ const oldRouteId = processFlowSelectBoundRouteId.value;
+ if (
+ oldRouteId !== null &&
+ oldRouteId !== undefined &&
+ oldRouteId !== "" &&
+ String(oldRouteId) !== String(finalRouteId)
+ ) {
+ try {
+ await ElMessageBox.confirm(
+ "璇ヨ鍗曞凡缁戝畾宸ヨ壓璺嚎锛屾槸鍚︾‘瀹氭洿鎹紵",
+ "鎻愮ず",
+ {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ }
+ );
+ } catch {
+ return;
}
}
- })
-}
-const submitProductEdit = () => {
- productForm.value.salesLedgerId = currentId.value
- addOrUpdateSalesLedgerProduct(productForm.value).then(res => {
- proxy.$modal.msgSuccess("鎻愪氦鎴愬姛")
- closeProductDia()
- getSalesLedgerWithProducts({id: currentId.value, type: 1}).then(res => {
- productData.value = res.productData
- })
- })
-}
-// 鍒犻櫎浜у搧
-const deleteProduct = () => {
- if (productSelectedRows.value.length === 0) {
- proxy.$modal.msgWarning('璇烽�夋嫨鏁版嵁')
- return
+
+ proxy?.$modal?.loading?.("姝e湪缁戝畾宸ヨ壓璺嚎锛岃绋嶅��...");
+ try {
+ await saleProcessBind({
+ salesLedgerId: ledgerRow.id,
+ processRouteId: finalRouteId,
+ });
+
+ proxy?.$modal?.msgSuccess?.("宸ヨ壓璺嚎缁戝畾鎴愬姛");
+ processFlowSelectDialogVisible.value = false;
+ // 缁戝畾鍚庡埛鏂板垪琛紝纭繚鎿嶄綔鍒楀啀娆$偣鍑昏兘鍥炴樉缁戝畾
+ await getList();
+ } catch (e) {
+ proxy?.$modal?.msgError?.("缁戝畾澶辫触锛岃绋嶅悗閲嶈瘯");
+ } finally {
+ proxy?.$modal?.closeLoading?.();
+ }
+ };
+
+ // 鑾峰彇浜у搧澶х被tree鏁版嵁
+ const getProductOptions = () => {
+ // 杩斿洖 Promise锛屼究浜庡湪缂栬緫浜у搧鏃剁瓑寰呭姞杞藉畬鎴�
+ return productTreeList().then(res => {
+ productOptions.value = convertIdToValue(res);
+ return productOptions.value;
+ });
+ };
+ const formattedNumber = (row, column, cellValue) => {
+ return parseFloat(cellValue).toFixed(2);
+ };
+ // 鑾峰彇tree瀛愭暟鎹�
+ const getModels = value => {
+ // 浜у搧澶х被鍙樺寲鏃讹紝閲嶇疆瑙勬牸鍨嬪彿涓庡帤搴︼紝閬垮厤鏃у�兼畫鐣�
+ productForm.value.productModelId = null;
+ productForm.value.specificationModel = "";
+ productForm.value.thickness = null;
+
+ if (!value) {
+ productForm.value.productCategory = "";
+ modelOptions.value = [];
+ return;
+ }
+
+ productForm.value.productCategory = findNodeById(productOptions.value, value);
+ modelList({ id: value }).then(res => {
+ modelOptions.value = res || [];
+ });
+ };
+ const getProductModel = value => {
+ const index = modelOptions.value.findIndex(item => item.id === value);
+ if (index !== -1) {
+ productForm.value.specificationModel = modelOptions.value[index].model;
+ const selectedModel = modelOptions.value[index];
+ const modelThickness =
+ selectedModel?.thickness ??
+ selectedModel?.modelThickness ??
+ selectedModel?.thick ??
+ null;
+ productForm.value.thickness =
+ modelThickness === null ||
+ modelThickness === undefined ||
+ modelThickness === ""
+ ? null
+ : Number(modelThickness);
+ } else {
+ productForm.value.specificationModel = null;
+ productForm.value.thickness = null;
+ }
+ };
+ const filterProductCategoryNode = (value, data) => {
+ if (!value) return true;
+ return String(data?.label || "")
+ .toLowerCase()
+ .includes(String(value).toLowerCase());
+ };
+ const findNodeById = (nodes, productId) => {
+ for (let i = 0; i < nodes.length; i++) {
+ if (nodes[i].value === productId) {
+ return nodes[i].label; // 鎵惧埌鑺傜偣锛岃繑鍥炶鑺傜偣
+ }
+ if (nodes[i].children && nodes[i].children.length > 0) {
+ const foundNode = findNodeById(nodes[i].children, productId);
+ if (foundNode) {
+ return foundNode; // 鍦ㄥ瓙鑺傜偣涓壘鍒帮紝杩斿洖璇ヨ妭鐐�
+ }
+ }
+ }
+ return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull
+ };
+ function convertIdToValue(data, level = 0) {
+ return data.map(item => {
+ const { id, children, ...rest } = item;
+ const hasChildren = Array.isArray(children) && children.length > 0;
+ const newItem = {
+ ...rest,
+ value: id, // 灏� id 鏀逛负 value
+ // 浠呭厑璁稿彾瀛愯妭鐐硅閫夋嫨锛堟湁瀛愯妭鐐圭殑鍒嗙被鑺傜偣缁熶竴绂佺敤锛�
+ disabled: Boolean(rest?.disabled) || hasChildren,
+ };
+ if (hasChildren) {
+ newItem.children = convertIdToValue(children, level + 1);
+ }
+
+ return newItem;
+ });
}
- if (operationType.value === 'add') {
- productSelectedRows.value.forEach(selectedRow => {
- const index = productData.value.findIndex(product => product.id === selectedRow.id);
- if (index !== -1) {
- productData.value.splice(index, 1);
+ // 鏍规嵁鍚嶇О鍙嶆煡浜у搧澶х被 id锛屼究浜庝粎瀛樺悕绉版椂鐨勫弽鏄�
+ function findNodeIdByLabel(nodes, label) {
+ if (!label) return null;
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i];
+ if (node.label === label) return node.value;
+ if (node.children && node.children.length > 0) {
+ const found = findNodeIdByLabel(node.children, label);
+ if (found !== null && found !== undefined) return found;
+ }
+ }
+ return null;
+ }
+ // 琛ㄦ牸閫夋嫨鏁版嵁
+ const handleSelectionChange = selection => {
+ // 杩囨护鎺夊瓙鏁版嵁
+ selectedRows.value = selection.filter(item => item.children !== undefined);
+ console.log("selection", selectedRows.value);
+ };
+ const productSelected = selectedRows => {
+ productSelectedRows.value = selectedRows;
+ };
+ const expandedRowKeys = ref([]);
+ // 灞曞紑琛�
+ const expandChange = (row, expandedRows) => {
+ if (expandedRows.length > 0) {
+ expandedRowKeys.value = [];
+ try {
+ productList({ salesLedgerId: row.id, type: 1 }).then(res => {
+ const index = tableData.value.findIndex(item => item.id === row.id);
+ if (index > -1) {
+ tableData.value[index].children = res.data;
+ }
+ expandedRowKeys.value.push(row.id);
+ });
+ } catch (error) {
+ console.log(error);
+ }
+ } else {
+ expandedRowKeys.value = [];
+ }
+ };
+
+ // 娣诲姞琛ㄨ绫诲悕鏂规硶
+ const tableRowClassName = ({ row }) => {
+ if (!row.deliveryDate) return "";
+ if (row.isFh) return "";
+
+ const diff = row.deliveryDaysDiff;
+ if (diff === 15) {
+ return "yellow";
+ } else if (diff === 10) {
+ return "pink";
+ } else if (diff === 2) {
+ return "purple";
+ } else if (diff < 2) {
+ return "red";
+ }
+ };
+ // 涓昏〃鍚堣鏂规硶
+ const summarizeMainTable = param => {
+ return proxy.summarizeTable(param, [
+ "contractAmount",
+ "taxInclusiveTotalPrice",
+ "taxExclusiveTotalPrice",
+ ]);
+ };
+ // 瀛愯〃鍚堣鏂规硶
+ const summarizeChildrenTable = param => {
+ return proxy.summarizeTable(param, [
+ "taxInclusiveUnitPrice",
+ "taxInclusiveTotalPrice",
+ "taxExclusiveTotalPrice",
+ ]);
+ };
+ // 鎵撳紑寮规
+ const openForm = async (type, row) => {
+ operationType.value = type;
+ form.value = {};
+ productData.value = [];
+ selectedQuotation.value = null;
+ let userLists = await userListNoPage();
+ userList.value = userLists.data;
+ customerList().then(res => {
+ customerOption.value = res;
+ });
+ form.value.entryPerson = userStore.id;
+ if (type === "add") {
+ // 鏂板鏃惰缃綍鍏ユ棩鏈熶负褰撳ぉ
+ form.value.entryDate = getCurrentDate();
+ // 绛捐鏃ユ湡榛樿涓哄綋澶�
+ form.value.executionDate = getCurrentDate();
+ form.value.customerRemarks = "";
+ } else {
+ currentId.value = row.id;
+ getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => {
+ form.value = { ...res };
+ form.value.entryPerson = Number(res.entryPerson);
+ // 瀛楁鍚嶅吋瀹癸細鍚庣鍙兘杩斿洖 customer_remarks
+ form.value.customerRemarks =
+ res?.customerRemarks ?? res?.customer_remarks ?? "";
+ productData.value = form.value.productData;
+ fileList.value = form.value.salesLedgerFiles;
+ });
+ }
+ // let userAll = await userStore.getInfo()
+ // userList.value.forEach(element => {
+ // if(userAll.user.nickName === element.nickName && userAll.user.userName === element.userName) {
+ // form.value.entryPerson = userAll.user.userId // 璁剧疆榛樿涓氬姟鍛樹负褰撳墠鐢ㄦ埛
+ // }
+ // });
+ form.value.entryDate = getCurrentDate(); // 璁剧疆榛樿褰曞叆鏃ユ湡涓哄綋鍓嶆棩鏈�
+ if (type === "add") {
+ form.value.deliveryDate = dayjs(form.value.entryDate)
+ .add(7, "day")
+ .format("YYYY-MM-DD");
+ }
+ dialogFormVisible.value = true;
+ };
+
+ // 鎵撳紑鎶ヤ环鍗曢�夋嫨寮圭獥锛堜粎瀹℃壒閫氳繃锛�
+ const openQuotationDialog = async () => {
+ if (operationType.value === "view") return;
+ quotationDialogVisible.value = true;
+ // 鎵撳紑寮圭獥鏃堕噸缃垎椤靛埌绗竴椤�
+ quotationPage.current = 1;
+ // 鍏堢‘淇濆鎴峰垪琛ㄥ凡鍔犺浇锛屼究浜庡悗缁洖濉� customerId
+ if (!customerOption.value || customerOption.value.length === 0) {
+ try {
+ const res = await customerList();
+ customerOption.value = res;
+ } catch (e) {
+ // ignore锛屽厑璁哥敤鎴峰悗缁墜鍔ㄩ�夋嫨瀹㈡埛
+ }
+ }
+ await fetchQuotationList();
+ };
+
+ const fetchQuotationList = async () => {
+ quotationLoading.value = true;
+ try {
+ const params = {
+ // 鍚庣鍒嗛〉瀛楁锛歝urrent / size
+ current: quotationPage.current,
+ size: quotationPage.size,
+ ...quotationSearchForm,
+ status: "閫氳繃",
+ };
+ const res = await getQuotationList(params);
+ quotationList.value = res?.data?.records || [];
+ quotationPage.total = res?.data?.total || 0;
+ } finally {
+ quotationLoading.value = false;
+ }
+ };
+
+ const resetQuotationSearch = async () => {
+ quotationSearchForm.quotationNo = "";
+ quotationSearchForm.customer = "";
+ quotationPage.current = 1;
+ await fetchQuotationList();
+ };
+
+ // 鎶ヤ环鍗曞脊妗嗗垎椤靛垏鎹�
+ const quotationPaginationChange = obj => {
+ quotationPage.current = obj.page;
+ quotationPage.size = obj.limit;
+ fetchQuotationList();
+ };
+
+ // 閫変腑鎶ヤ环鍗曞悗鍥炲~鍒板彴璐﹁〃鍗�
+ const applyQuotation = row => {
+ if (!row) return;
+ selectedQuotation.value = row;
+
+ // 涓氬姟鍛�
+ form.value.salesman = (row.salesperson || "").trim();
+
+ // 瀹㈡埛鍚嶇О -> customerId
+ const qCustomerName = String(row.customer || "").trim();
+ const customer = (customerOption.value || []).find(c => {
+ const name = String(c.customerName || "").trim();
+ return (
+ name === qCustomerName ||
+ name.includes(qCustomerName) ||
+ qCustomerName.includes(name)
+ );
+ });
+ if (customer?.id) {
+ form.value.customerId = customer.id;
+ } else {
+ // 濡傛灉鎵句笉鍒帮紝淇濈暀鍘熷�硷紙鍏佽鐢ㄦ埛鎵嬪姩閫夋嫨/涓嶆墦鏂凡鏈夎緭鍏ワ級
+ form.value.customerId = form.value.customerId || "";
+ }
+
+ // 浜у搧淇℃伅鏄犲皠锛氭姤浠� products -> 鍙拌处 productData
+ const products = Array.isArray(row.products) ? row.products : [];
+ productData.value = products.map(p => {
+ const quantity = Number(p.quantity ?? 0) || 0;
+ const unitPrice = Number(p.unitPrice ?? 0) || 0;
+ const settlePieceArea = Number(p.settlePieceArea ?? 0) || 1;
+ const taxRate = "13"; // 榛樿 13%锛屼究浜庣洿鎺ユ彁浜わ紙濡傞渶鍙湪浜у搧涓嚜琛屼慨鏀癸級
+ const taxInclusiveTotalPrice = (
+ unitPrice *
+ settlePieceArea *
+ quantity
+ ).toFixed(2);
+ const taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(
+ taxInclusiveTotalPrice,
+ taxRate
+ );
+ return {
+ // 鍙拌处瀛楁
+ productCategory: p.product || p.productName || "",
+ specificationModel: p.specification || "",
+ thickness: p.thickness,
+ quantity: quantity,
+ taxRate: taxRate,
+ taxInclusiveUnitPrice: unitPrice.toFixed(2),
+ taxInclusiveTotalPrice: taxInclusiveTotalPrice,
+ taxExclusiveTotalPrice: taxExclusiveTotalPrice,
+ invoiceType: "澧炴櫘绁�",
+ // 鏂板锛氶粯璁ゅ�硷紙閬垮厤鍚庣画鎻愪氦鏃跺瓧娈电己澶憋級
+ width: 0,
+ height: 0,
+ actualPieceArea: 0,
+ actualTotalArea: 0,
+ settlePieceArea: 0,
+ settleTotalArea: 0,
+ processRequirement: "",
+ floorCode: "",
+ remark: "",
+ salesProductProcessList: [],
+ };
+ });
+
+ quotationDialogVisible.value = false;
+ };
+ function changs(val) {
+ console.log(val);
+ }
+ // 涓婁紶鍓嶆牎妫�
+ function handleBeforeUpload(file) {
+ // 鏍℃鏂囦欢澶у皬
+ // if (file.size > 1024 * 1024 * 10) {
+ // proxy.$modal.msgError("涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃10MB!");
+ // return false;
+ // }
+ proxy.$modal.loading("姝e湪涓婁紶鏂囦欢锛岃绋嶅��...");
+ return true;
+ }
+ // 涓婁紶澶辫触
+ function handleUploadError(err) {
+ proxy.$modal.msgError("涓婁紶鏂囦欢澶辫触");
+ proxy.$modal.closeLoading();
+ }
+ // 涓婁紶鎴愬姛鍥炶皟
+ function handleUploadSuccess(res, file, uploadFiles) {
+ proxy.$modal.closeLoading();
+ if (res.code === 200) {
+ file.tempId = res.data.tempId;
+ proxy.$modal.msgSuccess("涓婁紶鎴愬姛");
+ } else {
+ proxy.$modal.msgError(res.msg);
+ proxy.$refs.fileUpload.handleRemove(file);
+ }
+ }
+ // 绉婚櫎鏂囦欢
+ function handleRemove(file) {
+ if (operationType.value === "edit") {
+ let ids = [];
+ ids.push(file.id);
+ delLedgerFile(ids).then(res => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ });
+ }
+ }
+ // 鎻愪氦琛ㄥ崟
+ const submitForm = () => {
+ proxy.$refs["formRef"].validate(valid => {
+ if (valid) {
+ console.log("productData.value--", productData.value);
+ // 琛屽唴缂栬緫鏈繚瀛樻椂涓嶅厑璁告彁浜わ紝閬垮厤鑴忔暟鎹�/涓存椂瀛楁杩涘叆鍚庣
+ const hasEditingRow = (productData.value || []).some(
+ r => r && r.__editing
+ );
+ if (hasEditingRow) {
+ proxy.$modal.msgWarning("浜у搧淇℃伅瀛樺湪鏈繚瀛樼殑缂栬緫琛岋紝璇峰厛淇濆瓨鎴栧彇娑�");
+ return;
+ }
+ if (productData.value !== null && productData.value.length > 0) {
+ const cleanedProducts = (productData.value || []).map(p => {
+ if (!p || typeof p !== "object") return p;
+ const {
+ __editing,
+ __isNew,
+ __backup,
+ __productCategoryId,
+ __tempKey,
+ __otherAmountPopoverVisible,
+ ...rest
+ } = p;
+ rest.taxRate = Number(rest.taxRate ?? 0) || 0;
+ rest.quantity = Number(rest.quantity ?? 0) || 0;
+ return rest;
+ });
+ form.value.productData = proxy.HaveJson(cleanedProducts);
+ } else {
+ proxy.$modal.msgWarning("璇锋坊鍔犱骇鍝佷俊鎭�");
+ return;
+ }
+ let tempFileIds = [];
+ if (fileList.value !== null && fileList.value.length > 0) {
+ tempFileIds = fileList.value.map(item => item.tempId);
+ }
+ form.value.tempFileIds = tempFileIds;
+ form.value.type = 1;
+ const submitPayload = { ...form.value };
+ delete submitPayload.paymentMethod;
+ addOrUpdateSalesLedger(submitPayload).then(res => {
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+ closeDia();
+ getList();
+ });
}
});
- } else {
- let ids = []
- if (productSelectedRows.value.length > 0) {
- ids = productSelectedRows.value.map(item => item.id);
+ };
+ // 鍏抽棴寮规
+ const closeDia = () => {
+ proxy.resetForm("formRef");
+ dialogFormVisible.value = false;
+ };
+
+ const productIndex = ref(0);
+ // 鎵撳紑浜у搧寮规
+ const openProductForm = async (type, row, index) => {
+ // 缂栬緫鏃舵鏌ヤ骇鍝佹槸鍚﹀凡鍙戣揣鎴栧鏍搁�氳繃
+ if (type === "edit" && isProductShipped(row)) {
+ proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳界紪杈�");
+ return;
}
- ElMessageBox.confirm(
- '閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�',
- '瀵煎嚭', {
- confirmButtonText: '纭',
- cancelButtonText: '鍙栨秷',
- type: 'warning',
+
+ productOperationType.value = type;
+ productForm.value = {};
+ proxy.resetForm("productFormRef");
+ // 纭繚澶氶�夐」榛樿鏄暟缁勶紝閬垮厤 el-select multiple 鎶ラ敊
+ productForm.value.salesProductProcessList = [];
+ otherAmountAddDialogVisible.value = false;
+ otherAmountAddId.value = null;
+ if (type === "edit") {
+ productForm.value = { ...row };
+
+ // 瀛楁鍛藉悕鍏煎锛氫紭鍏堥┘宄帮紙濡� actualPieceArea锛夛紝鍏煎鍚庣鍙兘杩斿洖涓嬪垝绾匡紙濡� actual_piece_area锛�
+ productForm.value.actualPieceArea =
+ row?.actualPieceArea ?? row?.actual_piece_area ?? 0;
+ productForm.value.actualTotalArea =
+ row?.actualTotalArea ?? row?.actual_total_area ?? 0;
+ productForm.value.settlePieceArea =
+ row?.settlePieceArea ?? row?.settle_piece_area ?? 0;
+ productForm.value.settleTotalArea =
+ row?.settleTotalArea ?? row?.settle_total_area ?? 0;
+
+ // 鍔犲伐瑕佹眰/澶囨敞鍏煎锛氬悗绔彲鑳戒娇鐢ㄥ叾瀹冨懡鍚�
+ productForm.value.processRequirement =
+ row?.processRequirement ?? row?.process_requirement ?? "";
+ productForm.value.remark = row?.remark ?? row?.remarks ?? "";
+ productForm.value.floorCode = row?.floorCode ?? row?.floor_code ?? "";
+ // 宸ヨ壓娴佺▼閰嶇疆缁戝畾瀛楁锛堝悗缁敱鍚庣纭瀛楁鍚嶏級
+ productForm.value.processFlowConfigId =
+ row?.processFlowConfigId ?? row?.process_flow_config_id ?? null;
+
+ // 鍛ㄩ暱鍥炴樉锛堝鍚庣杩斿洖锛涙渶缁堜粛浠ュ叕寮忚绠椾负鍑嗭級
+ productForm.value.perimeter =
+ row?.perimeter ?? row?.heavyBoxPerimeter ?? row?.heavyboxPerimeter ?? 0;
+
+ // 鍚庣鐩存帴杩斿洖 thickness
+ productForm.value.thickness = row?.thickness;
+
+ productForm.value.salesProductProcessList =
+ normalizeOtherAmountsFromRow(row);
+ productIndex.value = index;
+ // 缂栬緫鏃舵牴鎹骇鍝佸ぇ绫诲悕绉板弽鏌� tree 鑺傜偣 id锛屽苟鍔犺浇瑙勬牸鍨嬪彿鍒楄〃
+ try {
+ const options =
+ productOptions.value && productOptions.value.length > 0
+ ? productOptions.value
+ : await getProductOptions();
+ const categoryId = findNodeIdByLabel(
+ options,
+ productForm.value.productCategory
+ );
+ if (categoryId) {
+ const models = await modelList({ id: categoryId });
+ modelOptions.value = models || [];
+ // 鏍规嵁褰撳墠瑙勬牸鍨嬪彿鍚嶇О鍙嶆煡骞惰缃� productModelId锛屼究浜庝笅鎷夋鏄剧ず宸查�夊��
+ const currentModel = (modelOptions.value || []).find(
+ m => m.model === productForm.value.specificationModel
+ );
+ if (currentModel) {
+ productForm.value.productModelId = currentModel.id;
+ }
}
- ).then(() => {
- delProduct(ids).then(res => {
- proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛")
- closeProductDia()
- getSalesLedgerWithProducts({id: currentId.value, type: 1}).then(res => {
- productData.value = res.productData
- })
+ } catch (e) {
+ // 鍔犺浇澶辫触鏃朵繚鎸佸彲缂栬緫锛屼笉涓柇寮圭獥
+ console.error("鍔犺浇浜у搧瑙勬牸鍨嬪彿澶辫触", e);
+ }
+
+ // 鏍规嵁褰撳墠瀹介珮閲嶆柊璁$畻鍛ㄩ暱涓庨潰绉�
+ recalcPerimeterFromWidthHeight();
+ recalcAreaFromWidthHeight();
+
+ // 鍥炴樉鈥滃叾浠栭噾棰濃�濆閫夛細鍏堟媺鍙栦笅鎷夐�夐」锛屽啀琛ラ綈 processName
+ await fetchOtherAmountSelectOptions(true);
+ mergeOtherAmountOptionsBySelection(
+ productForm.value.salesProductProcessList
+ );
+ productForm.value.salesProductProcessList = fillOtherAmountProcessName(
+ productForm.value.salesProductProcessList
+ );
+ } else {
+ getProductOptions();
+ // 鏂板鏃朵笅鎷夐�夐」鍔犺浇涓�娆″嵆鍙�
+ fetchOtherAmountSelectOptions(true);
+ }
+ productFormVisible.value = true;
+ };
+ // 鎻愪氦浜у搧琛ㄥ崟
+ const submitProduct = () => {
+ proxy.$refs["productFormRef"].validate(valid => {
+ if (valid) {
+ // 鍘氬害淇濈暀 15 浣嶅皬鏁帮紝閬垮厤鐢变簬娴偣璁$畻/杈撳叆瀵艰嚧绮惧害鍋忓樊
+ if (
+ productForm.value.thickness !== null &&
+ productForm.value.thickness !== undefined
+ ) {
+ productForm.value.thickness = Number(
+ Number(productForm.value.thickness).toFixed(15)
+ );
+ }
+
+ // 闈㈢Н/鎬昏瀛楁鍦ㄦ彁浜ゅ墠鍏滃簳璁$畻涓�娆�
+ recalcAreaTotals();
+ // 鎻愪氦鍏滃簳锛氱◣鐜�/鏁伴噺鏈~鏃舵寜鏁板瓧 0 浼犻��
+ productForm.value.taxRate = Number(productForm.value.taxRate ?? 0) || 0;
+ productForm.value.quantity = Number(productForm.value.quantity ?? 0) || 0;
+ // 鍏朵粬閲戦鍙彁浜� {id, processName, quantity}锛堝悗绔瓧娈碉細salesProductProcessList锛�
+ productForm.value.salesProductProcessList = (
+ Array.isArray(productForm.value.salesProductProcessList)
+ ? productForm.value.salesProductProcessList
+ : []
+ )
+ .map(it => ({
+ id: it?.id,
+ processName: it?.processName ?? "",
+ unitPrice: Number(it?.unitPrice ?? 0) || 0,
+ quantity: Number(it?.quantity ?? 0) || 0,
+ }))
+ .filter(it => it.id !== null && it.id !== undefined && it.id !== "");
+
+ if (operationType.value === "edit") {
+ submitProductEdit();
+ } else {
+ if (productOperationType.value === "add") {
+ productData.value.push({ ...productForm.value });
+ } else {
+ productData.value[productIndex.value] = { ...productForm.value };
+ }
+ closeProductDia();
+ }
+ }
+ });
+ };
+ const submitProductEdit = () => {
+ productForm.value.salesLedgerId = currentId.value;
+ productForm.value.type = 1;
+ addOrUpdateSalesLedgerProduct(productForm.value).then(res => {
+ proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+ closeProductDia();
+ getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then(res => {
+ productData.value = res.productData;
+ });
+ });
+ };
+ // 鍒犻櫎浜у搧
+ const deleteProduct = () => {
+ if (productSelectedRows.value.length === 0) {
+ proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+ return;
+ }
+
+ // 妫�鏌ユ槸鍚︽湁宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝�
+ const shippedProducts = productSelectedRows.value.filter(row =>
+ isProductShipped(row)
+ );
+ if (shippedProducts.length > 0) {
+ proxy.$modal.msgWarning("宸插彂璐ф垨瀹℃牳閫氳繃鐨勪骇鍝佷笉鑳藉垹闄�");
+ return;
+ }
+
+ if (operationType.value === "add") {
+ productSelectedRows.value.forEach(selectedRow => {
+ const index = productData.value.findIndex(product => {
+ if (!product || !selectedRow) return false;
+ // 鏂板琛� id 涓虹┖鏃讹紝鐢ㄤ复鏃� key 瀹氫綅
+ if (product.id != null && selectedRow.id != null) {
+ return String(product.id) === String(selectedRow.id);
+ }
+ return (
+ product.__tempKey &&
+ selectedRow.__tempKey &&
+ String(product.__tempKey) === String(selectedRow.__tempKey)
+ );
+ });
+ if (index !== -1) {
+ productData.value.splice(index, 1);
+ }
+ });
+ } else {
+ let ids = [];
+ if (productSelectedRows.value.length > 0) {
+ ids = productSelectedRows.value.map(item => item.id);
+ }
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
})
- }).catch(() => {
- proxy.$modal.msg("宸插彇娑�")
+ .then(() => {
+ delProduct(ids).then(res => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ closeProductDia();
+ getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then(
+ res => {
+ productData.value = res.productData;
+ }
+ );
+ });
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+ }
+ };
+ // 鍏抽棴浜у搧寮规
+ const closeProductDia = () => {
+ proxy.resetForm("productFormRef");
+ productFormVisible.value = false;
+ otherAmountAddDialogVisible.value = false;
+ otherAmountAddId.value = null;
+ };
+ // 瀵煎叆
+ const handleImport = () => {
+ importUpload.title = "瀵煎叆閿�鍞彴璐�";
+ importUpload.open = true;
+ if (importUploadRef.value) {
+ importUploadRef.value.clearFiles();
+ }
+ };
+
+ // 涓嬭浇瀵煎叆妯℃澘
+ const downloadTemplate = () => {
+ proxy.download("/sales/ledger/exportTemplate", {}, "閿�鍞彴璐﹀鍏ユā鏉�.xlsx");
+ };
+
+ // 鎻愪氦瀵煎叆鏂囦欢
+ const submitImportFile = () => {
+ importUpload.isUploading = true;
+ proxy.$refs["importUploadRef"].submit();
+ };
+
+ // 瀵煎嚭
+ const handleOut = () => {
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
})
-
- }
-}
-// 鍏抽棴浜у搧寮规
-const closeProductDia = () => {
- proxy.resetForm("productFormRef")
- productFormVisible.value = false
-}
-// 瀵煎嚭
-const handleOut = () => {
- ElMessageBox.confirm(
- '閫変腑鐨勫唴瀹瑰皢琚鍑猴紝鏄惁纭瀵煎嚭锛�',
- '瀵煎嚭', {
- confirmButtonText: '纭',
- cancelButtonText: '鍙栨秷',
- type: 'warning',
+ .then(() => {
+ proxy.download("/sales/ledger/export", {}, "閿�鍞彴璐�.xlsx");
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+ };
+ /** 鍒ゆ柇鍗曚釜浜у搧鏄惁宸插彂璐э紙鏍规嵁shippingStatus鍒ゆ柇锛屽凡鍙戣揣鎴栧鏍搁�氳繃涓嶅彲缂栬緫鍜屽垹闄わ級 */
+ const isProductShipped = product => {
+ if (!product) return false;
+ const status = String(product.shippingStatus || "").trim();
+ // 濡傛灉鍙戣揣鐘舵�佹槸"宸插彂璐�"鎴�"瀹℃牳閫氳繃"锛屽垯涓嶅彲缂栬緫鍜屽垹闄�
+ return status === "宸插彂璐�" || status === "瀹℃牳閫氳繃";
+ };
+
+ /** 鍒ゆ柇閿�鍞鍗曚笅鏄惁瀛樺湪宸插彂璐�/鍙戣揣瀹屾垚鐨勪骇鍝侊紙涓嶅彲鍒犻櫎锛� */
+ const hasShippedProducts = products => {
+ if (!products || !products.length) return false;
+ return products.some(p => {
+ const status = String(p.shippingStatus || "").trim();
+ // 鏈夊彂璐ф棩鏈熸垨杞︾墝鍙疯涓哄凡鍙戣揣
+ if (p.shippingDate || p.shippingCarNumber) return true;
+ // 宸茶繘琛屽彂璐с�佸彂璐у畬鎴愩�佸凡鍙戣揣 鍧囦笉鍙垹闄�
+ return (
+ status === "宸茶繘琛屽彂璐�" || status === "鍙戣揣瀹屾垚" || status === "宸插彂璐�"
+ );
+ });
+ };
+
+ // 鍒犻櫎
+ const handleDelete = async () => {
+ if (selectedRows.value.length === 0) {
+ proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+ return;
+ }
+ const ids = selectedRows.value.map(item => item.id);
+
+ // 妫�鏌ユ槸鍚︽湁宸茶繘琛屽彂璐ф垨鍙戣揣瀹屾垚鐨勯攢鍞鍗曪紝鑻ユ湁鍒欎笉鍏佽鍒犻櫎
+ const cannotDeleteNames = [];
+ for (const row of selectedRows.value) {
+ let products =
+ row.children && row.children.length > 0 ? row.children : null;
+ if (!products) {
+ try {
+ const res = await productList({ salesLedgerId: row.id, type: 1 });
+ products = res.data || [];
+ } catch {
+ products = [];
+ }
}
- ).then(() => {
- proxy.download("/sales/ledger/export", {}, '閿�鍞彴璐�.xlsx')
- }).catch(() => {
- proxy.$modal.msg("宸插彇娑�")
- })
-}
-// 鍒犻櫎
-const handleDelete = () => {
- let ids = []
- if (selectedRows.value.length > 0) {
- ids = selectedRows.value.map(item => item.id);
- } else {
- proxy.$modal.msgWarning('璇烽�夋嫨鏁版嵁')
- return
- }
- ElMessageBox.confirm(
- '閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�',
- '瀵煎嚭', {
- confirmButtonText: '纭',
- cancelButtonText: '鍙栨秷',
- type: 'warning',
+ if (hasShippedProducts(products)) {
+ cannotDeleteNames.push(row.salesContractNo || `ID:${row.id}`);
}
- ).then(() => {
- delLedger(ids).then(res => {
- proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛")
- getList()
+ }
+ if (cannotDeleteNames.length > 0) {
+ proxy.$modal.msgWarning(
+ "宸茶繘琛屽彂璐ф垨鍙戣揣瀹屾垚鐨勯攢鍞鍗曚笉鑳藉垹闄わ細" + cannotDeleteNames.join("銆�")
+ );
+ return;
+ }
+
+ ElMessageBox.confirm("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "瀵煎嚭", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
})
- }).catch(() => {
- proxy.$modal.msg("宸插彇娑�")
- })
-}
-getList()
+ .then(() => {
+ delLedger(ids).then(res => {
+ proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+ getList();
+ });
+ })
+ .catch(() => {
+ proxy.$modal.msg("宸插彇娑�");
+ });
+ };
+
+ const handlePrintCommand = async command => {
+ if (
+ command !== "finishedProcessCard" &&
+ command !== "salesOrder" &&
+ command !== "salesDeliveryNote"
+ )
+ return;
+ if (command === "salesDeliveryNote") {
+ if (selectedRows.value.length === 0) {
+ proxy.$modal.msgWarning("璇疯嚦灏戦�夋嫨涓�鏉¢攢鍞彴璐︽暟鎹繘琛屾墦鍗�");
+ return;
+ }
+ const customerNames = Array.from(
+ new Set(
+ selectedRows.value.map(item => String(item?.customerName ?? "").trim())
+ )
+ );
+ if (customerNames.length > 1) {
+ proxy.$modal.msgWarning("浠呮敮鎸佺浉鍚屽鎴峰悕绉扮殑閿�鍞彴璐﹀悎骞跺彂璐ф墦鍗�");
+ return;
+ }
+ } else if (selectedRows.value.length !== 1) {
+ proxy.$modal.msgWarning("璇烽�夋嫨涓�鏉¢攢鍞彴璐︽暟鎹繘琛屾墦鍗�");
+ return;
+ }
+
+ const selectedRow = selectedRows.value[0];
+ const selectedId = selectedRow?.id;
+ if (command === "salesDeliveryNote") {
+ const selectedIds = selectedRows.value
+ .map(item => item?.id)
+ .filter(id => id !== null && id !== undefined && id !== "");
+ if (selectedIds.length !== selectedRows.value.length) {
+ proxy.$modal.msgWarning("褰撳墠閫夋嫨鏁版嵁瀛樺湪缂哄皯ID鐨勮褰曪紝鏃犳硶鎵撳嵃");
+ return;
+ }
+ const loadingText =
+ command === "salesOrder"
+ ? "姝e湪鑾峰彇閿�鍞鍗曟暟鎹紝璇风◢鍊�..."
+ : command === "salesDeliveryNote"
+ ? "姝e湪鑾峰彇閿�鍞彂璐у崟鏁版嵁锛岃绋嶅��..."
+ : "姝e湪鑾峰彇鐢熶骇娴佺▼鍗℃暟鎹紝璇风◢鍊�...";
+ proxy.$modal.loading(loadingText);
+ try {
+ const res = await getSalesInvoices(selectedIds);
+ const salesInvoiceData = res?.data ?? {};
+ printSalesDeliveryNote(salesInvoiceData, selectedRow);
+ } catch (error) {
+ console.error("鎵撳嵃閿�鍞彂璐у崟澶辫触:", error);
+ proxy.$modal.msgError("鎵撳嵃澶辫触锛岃绋嶅悗閲嶈瘯");
+ } finally {
+ proxy.$modal.closeLoading();
+ }
+ return;
+ }
+ if (!selectedId) {
+ proxy.$modal.msgWarning("褰撳墠閫夋嫨鏁版嵁缂哄皯ID锛屾棤娉曟墦鍗�");
+ return;
+ }
+
+ const loadingText =
+ command === "salesOrder"
+ ? "姝e湪鑾峰彇閿�鍞鍗曟暟鎹紝璇风◢鍊�..."
+ : command === "salesDeliveryNote"
+ ? "姝e湪鑾峰彇閿�鍞彂璐у崟鏁版嵁锛岃绋嶅��..."
+ : "姝e湪鑾峰彇鐢熶骇娴佺▼鍗℃暟鎹紝璇风◢鍊�...";
+ proxy.$modal.loading(loadingText);
+ try {
+ if (command === "salesOrder") {
+ const res = await getSalesOrder(selectedId);
+ const salesOrderData = res?.data ?? {};
+ printSalesOrder(salesOrderData);
+ } else {
+ const res = await getProcessCard(selectedId);
+ const processCardData = res?.data ?? {};
+ printFinishedProcessCard(processCardData);
+ }
+ } catch (error) {
+ console.error(
+ command === "salesOrder"
+ ? "鎵撳嵃閿�鍞鍗曞け璐�:"
+ : command === "salesDeliveryNote"
+ ? "鎵撳嵃閿�鍞彂璐у崟澶辫触:"
+ : "鎵撳嵃鐢熶骇娴佺▼鍗″け璐�:",
+ error
+ );
+ proxy.$modal.msgError("鎵撳嵃澶辫触锛岃绋嶅悗閲嶈瘯");
+ } finally {
+ proxy.$modal.closeLoading();
+ }
+ };
+
+ const handlePrintLabel = async () => {
+ if (selectedRows.value.length !== 1) {
+ proxy.$modal.msgWarning("璇烽�夋嫨涓�鏉¢攢鍞彴璐︽暟鎹繘琛屾爣绛炬墦鍗�");
+ return;
+ }
+
+ const selectedId = selectedRows.value[0]?.id;
+ if (!selectedId) {
+ proxy.$modal.msgWarning("褰撳墠閫夋嫨鏁版嵁缂哄皯ID锛屾棤娉曟墦鍗版爣绛�");
+ return;
+ }
+
+ proxy.$modal.loading("姝e湪鑾峰彇鏍囩鏁版嵁锛岃绋嶅��...");
+ try {
+ const res = await getSalesLabel(selectedId);
+ const labelList = res?.data ?? [];
+ if (!Array.isArray(labelList) || labelList.length === 0) {
+ proxy.$modal.msgWarning("鏆傛棤鍙墦鍗版爣绛炬暟鎹�");
+ return;
+ }
+ printSalesLabel(labelList);
+ } catch (error) {
+ console.error("鎵撳嵃鏍囩澶辫触:", error);
+ proxy.$modal.msgError("鎵撳嵃鏍囩澶辫触锛岃绋嶅悗閲嶈瘯");
+ } finally {
+ proxy.$modal.closeLoading();
+ }
+ };
+
+ const mathNum = () => {
+ console.log("productForm.value", productForm.value);
+ if (!productForm.value.taxInclusiveUnitPrice) {
+ return;
+ }
+ if (!productForm.value.quantity) {
+ return;
+ }
+ const settlePieceArea = parseFloat(productForm.value.settlePieceArea) || 1;
+ // 鍚◣鎬讳环璁$畻 = 鍗曚环 * 缁撶畻闈㈢Н * 鏁伴噺 + 鍏朵粬閲戦鎬诲拰
+ const basePrice = proxy.calculateTaxIncludeTotalPrice(
+ productForm.value.taxInclusiveUnitPrice * settlePieceArea,
+ productForm.value.quantity
+ );
+ const otherAmountTotal = (
+ productForm.value.salesProductProcessList || []
+ ).reduce((total, item) => {
+ return total + (Number(item.unitPrice) || 0) * (Number(item.quantity) || 0);
+ }, 0);
+ productForm.value.taxInclusiveTotalPrice = (
+ parseFloat(basePrice) + otherAmountTotal
+ ).toFixed(2);
+ if (productForm.value.taxRate) {
+ // 涓嶅惈绋庢�讳环璁$畻
+ productForm.value.taxExclusiveTotalPrice =
+ proxy.calculateTaxExclusiveTotalPrice(
+ productForm.value.taxInclusiveTotalPrice,
+ productForm.value.taxRate
+ );
+ }
+ };
+
+ // 鏂板锛氬昂瀵�(瀹介珮)涓庨潰绉�(鍗曠墖/鎬昏)鑱斿姩
+ const recalcAreaTotals = () => {
+ const qty = Number(productForm.value.quantity ?? 0) || 0;
+ const actualPiece = Number(productForm.value.actualPieceArea ?? 0) || 0;
+ const settlePiece = Number(productForm.value.settlePieceArea ?? 0) || 0;
+
+ productForm.value.actualTotalArea = Number((actualPiece * qty).toFixed(5));
+ productForm.value.settleTotalArea = Number((settlePiece * qty).toFixed(5));
+ };
+
+ // 鏂板锛氬懆闀�(cm)锛堥噸绠県eavyBox鍛ㄩ暱锛�
+ // width/height 鍗曚綅涓� mm锛屽洜姝ゅ懆闀�(cm)闇�瑕侀櫎浠� 10
+ const recalcPerimeterFromWidthHeight = () => {
+ const width = Number(productForm.value.width ?? 0) || 0;
+ const height = Number(productForm.value.height ?? 0) || 0;
+
+ if (width <= 0 || height <= 0) {
+ productForm.value.perimeter = 0;
+ return;
+ }
+
+ // 鍛ㄩ暱 = (瀹� + 楂�) * 2锛屽崟浣嶄粠 mm 杞负 cm锛�/10
+ productForm.value.perimeter = Number(
+ (((width + height) * 2) / 10).toFixed(2)
+ );
+ };
+
+ const recalcAreaFromWidthHeight = () => {
+ const width = Number(productForm.value.width ?? 0) || 0;
+ const height = Number(productForm.value.height ?? 0) || 0;
+
+ if (width <= 0 || height <= 0) {
+ // 瀹介珮涓虹┖/涓�0鏃讹紝鎶婂崟鐗囬潰绉笌鎬婚潰绉疆涓�0
+ productForm.value.actualPieceArea = 0;
+ productForm.value.actualTotalArea = 0;
+ productForm.value.perimeter = 0;
+
+ // 鍙湁鍦ㄧ粨绠楀崟鐗囬潰绉篃涓虹┖/涓�0鏃讹紝鎵嶅悓姝ョ疆0锛岄伩鍏嶈鐩栫敤鎴锋墜鍔ㄥ~鍐�
+ const settlePiece = Number(productForm.value.settlePieceArea ?? 0) || 0;
+ if (!settlePiece) {
+ productForm.value.settlePieceArea = 0;
+ }
+ productForm.value.settleTotalArea = Number(
+ (
+ (Number(productForm.value.settlePieceArea ?? 0) || 0) *
+ (Number(productForm.value.quantity ?? 0) || 0)
+ ).toFixed(5)
+ );
+ return;
+ }
+
+ const computedPieceArea = (width * height) / 1e6; // mm*mm -> 銕�
+ const computed = Number(computedPieceArea.toFixed(5));
+
+ productForm.value.actualPieceArea = computed;
+ productForm.value.settlePieceArea = computed;
+
+ recalcPerimeterFromWidthHeight();
+ recalcAreaTotals();
+ // 闈㈢Н鏇存柊鍚庯紝閲嶆柊璁$畻鍚◣鎬讳环 = 鍗曚环 * 缁撶畻闈㈢Н * 鏁伴噺
+ calculateFromUnitPrice(true);
+ };
+
+ // 鏍规嵁鍚◣鎬讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
+ const calculateFromTotalPrice = () => {
+ if (isCalculating.value) return;
+
+ const totalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
+ const quantity = parseFloat(productForm.value.quantity);
+
+ if (!totalPrice || !quantity || quantity <= 0) {
+ return;
+ }
+
+ isCalculating.value = true;
+
+ // 璁$畻鍚◣鍗曚环 = (鍚◣鎬讳环 - 鍏朵粬閲戦鎬诲拰) / 鏁伴噺
+ const otherAmountTotal = (
+ productForm.value.salesProductProcessList || []
+ ).reduce((total, item) => {
+ return total + (Number(item.unitPrice) || 0) * (Number(item.quantity) || 0);
+ }, 0);
+ const basePrice = totalPrice - otherAmountTotal;
+ productForm.value.taxInclusiveUnitPrice = (basePrice / quantity).toFixed(2);
+
+ // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
+ if (productForm.value.taxRate) {
+ productForm.value.taxExclusiveTotalPrice =
+ proxy.calculateTaxExclusiveTotalPrice(
+ totalPrice,
+ productForm.value.taxRate
+ );
+ }
+
+ isCalculating.value = false;
+ };
+
+ // 鏍规嵁涓嶅惈绋庢�讳环璁$畻鍚◣鍗曚环鍜屾暟閲�
+ const calculateFromExclusiveTotalPrice = () => {
+ // if (!productForm.value.taxRate) {
+ // proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+ // return;
+ // }
+ if (isCalculating.value) return;
+
+ const exclusiveTotalPrice = parseFloat(
+ productForm.value.taxExclusiveTotalPrice
+ );
+ const quantity = parseFloat(productForm.value.quantity);
+ const taxRate = parseFloat(productForm.value.taxRate);
+
+ if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) {
+ return;
+ }
+
+ isCalculating.value = true;
+
+ // 鍏堣绠楀惈绋庢�讳环 = 涓嶅惈绋庢�讳环 / (1 - 绋庣巼/100)
+ const taxRateDecimal = taxRate / 100;
+ const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal);
+ productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2);
+
+ // 璁$畻鍚◣鍗曚环 = (鍚◣鎬讳环 - 鍏朵粬閲戦鎬诲拰) / 鏁伴噺
+ const otherAmountTotal = (
+ productForm.value.salesProductProcessList || []
+ ).reduce((total, item) => {
+ return total + (Number(item.unitPrice) || 0) * (Number(item.quantity) || 0);
+ }, 0);
+ const basePrice = inclusiveTotalPrice - otherAmountTotal;
+ productForm.value.taxInclusiveUnitPrice = (basePrice / quantity).toFixed(2);
+
+ isCalculating.value = false;
+ };
+
+ // 鏍规嵁鏁伴噺鍙樺寲璁$畻鎬讳环
+ const calculateFromQuantity = () => {
+ // if (!productForm.value.taxRate) {
+ // proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+ // return;
+ // }
+ if (isCalculating.value) return;
+
+ const quantity = parseFloat(productForm.value.quantity);
+ const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
+ const settlePieceArea = parseFloat(productForm.value.settlePieceArea) || 1;
+
+ if (!quantity || quantity <= 0 || !unitPrice) {
+ return;
+ }
+
+ isCalculating.value = true;
+
+ // 璁$畻鍚◣鎬讳环 = 鍗曚环 * 缁撶畻闈㈢Н * 鏁伴噺 + 鍏朵粬閲戦鎬诲拰
+ const basePrice = unitPrice * settlePieceArea * quantity;
+ const otherAmountTotal = (
+ productForm.value.salesProductProcessList || []
+ ).reduce((total, item) => {
+ return total + (Number(item.unitPrice) || 0) * (Number(item.quantity) || 0);
+ }, 0);
+ productForm.value.taxInclusiveTotalPrice = (
+ basePrice + otherAmountTotal
+ ).toFixed(2);
+
+ // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
+ if (productForm.value.taxRate) {
+ productForm.value.taxExclusiveTotalPrice =
+ proxy.calculateTaxExclusiveTotalPrice(
+ productForm.value.taxInclusiveTotalPrice,
+ productForm.value.taxRate
+ );
+ }
+
+ isCalculating.value = false;
+ };
+
+ // 鏍规嵁鍚◣鍗曚环鍙樺寲璁$畻鎬讳环
+ const calculateFromUnitPrice = (silent = false) => {
+ // if (!productForm.value.taxRate) {
+ // if (!silent) proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+ // return;
+ // }
+ if (isCalculating.value) return;
+
+ const quantity = parseFloat(productForm.value.quantity);
+ const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
+ const settlePieceArea = parseFloat(productForm.value.settlePieceArea) || 1;
+
+ if (!quantity || quantity <= 0 || !unitPrice) {
+ return;
+ }
+
+ isCalculating.value = true;
+
+ // 璁$畻鍚◣鎬讳环 = 鍗曚环 * 缁撶畻闈㈢Н * 鏁伴噺 + 鍏朵粬閲戦鎬诲拰
+ const basePrice = unitPrice * settlePieceArea * quantity;
+ const otherAmountTotal = (
+ productForm.value.salesProductProcessList || []
+ ).reduce((total, item) => {
+ return total + (Number(item.unitPrice) || 0) * (Number(item.quantity) || 0);
+ }, 0);
+ productForm.value.taxInclusiveTotalPrice = (
+ basePrice + otherAmountTotal
+ ).toFixed(2);
+
+ // 濡傛灉鏈夌◣鐜囷紝璁$畻涓嶅惈绋庢�讳环
+ if (productForm.value.taxRate) {
+ productForm.value.taxExclusiveTotalPrice =
+ proxy.calculateTaxExclusiveTotalPrice(
+ productForm.value.taxInclusiveTotalPrice,
+ productForm.value.taxRate
+ );
+ }
+
+ isCalculating.value = false;
+ };
+
+ // 鏍规嵁绋庣巼鍙樺寲璁$畻涓嶅惈绋庢�讳环
+ const calculateFromTaxRate = () => {
+ // if (!productForm.value.taxRate) {
+ // proxy.$modal.msgWarning("璇峰厛閫夋嫨绋庣巼");
+ // return;
+ // }
+ if (isCalculating.value) return;
+
+ const inclusiveTotalPrice = parseFloat(
+ productForm.value.taxInclusiveTotalPrice
+ );
+ const taxRate = parseFloat(productForm.value.taxRate);
+
+ if (!inclusiveTotalPrice || !taxRate) {
+ return;
+ }
+
+ isCalculating.value = true;
+
+ // 璁$畻涓嶅惈绋庢�讳环
+ productForm.value.taxExclusiveTotalPrice =
+ proxy.calculateTaxExclusiveTotalPrice(inclusiveTotalPrice, taxRate);
+
+ isCalculating.value = false;
+ };
+ /**
+ * 鑾峰彇鍙戣揣鐘舵�佹枃鏈�
+ * @param row 琛屾暟鎹�
+ */
+ const getShippingStatusText = row => {
+ // 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屾樉绀�"宸插彂璐�"
+ if (row.shippingDate || row.shippingCarNumber) {
+ return "宸插彂璐�";
+ }
+
+ // 鑾峰彇鍙戣揣鐘舵�佸瓧娈�
+ const status = row.shippingStatus;
+
+ // 濡傛灉鐘舵�佷负绌烘垨鏈畾涔夛紝榛樿涓�"寰呭彂璐�"
+ if (status === null || status === undefined || status === "") {
+ return "寰呭彂璐�";
+ }
+
+ // 鐘舵�佹槸瀛楃涓�
+ const statusStr = String(status).trim();
+ const statusTextMap = {
+ 寰呭彂璐�: "寰呭彂璐�",
+ 寰呭鏍�: "寰呭鏍�",
+ 瀹℃牳涓�: "瀹℃牳涓�",
+ 瀹℃牳鎷掔粷: "瀹℃牳鎷掔粷",
+ 瀹℃牳閫氳繃: "瀹℃牳閫氳繃",
+ 宸插彂璐�: "宸插彂璐�",
+ };
+ return statusTextMap[statusStr] || "寰呭彂璐�";
+ };
+
+ /**
+ * 鑾峰彇鍙戣揣鐘舵�佹爣绛剧被鍨嬶紙棰滆壊锛�
+ * @param row 琛屾暟鎹�
+ */
+ const getShippingStatusType = row => {
+ // 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屾樉绀虹豢鑹�
+ if (row.shippingDate || row.shippingCarNumber) {
+ return "success";
+ }
+
+ // 鑾峰彇鍙戣揣鐘舵�佸瓧娈�
+ const status = row.shippingStatus;
+
+ // 濡傛灉鐘舵�佷负绌烘垨鏈畾涔夛紝榛樿涓虹伆鑹诧紙寰呭彂璐э級
+ if (status === null || status === undefined || status === "") {
+ return "info";
+ }
+
+ // 鐘舵�佹槸瀛楃涓�
+ const statusStr = String(status).trim();
+ const typeTextMap = {
+ 寰呭彂璐�: "info",
+ 寰呭鏍�: "info",
+ 瀹℃牳涓�: "warning",
+ 瀹℃牳鎷掔粷: "danger",
+ 瀹℃牳閫氳繃: "success",
+ 宸插彂璐�: "success",
+ };
+ return typeTextMap[statusStr] || "info";
+ };
+
+ /**
+ * 鍒ゆ柇鏄惁鍙互鍙戣揣
+ * 鍙湁鍦ㄤ骇鍝佺姸鎬佹槸鍏呰冻锛屽彂璐х姸鎬佹槸寰呭彂璐у拰瀹℃牳鎷掔粷鐨勬椂鍊欐墠鍙互鍙戣揣
+ * @param row 琛屾暟鎹�
+ */
+ const canShip = row => {
+ // 浜у搧鐘舵�佸繀椤绘槸鍏呰冻锛坅pproveStatus === 1锛�
+ if (row.approveStatus !== 1) {
+ return false;
+ }
+
+ // 濡傛灉鍚庣杩斿洖浜嗗彴璐︾骇鍙戣揣鐘舵�侊紙deliveryStatus锛�
+ // 1=宸插彂璐э紝鍒欑姝㈠啀娆″彂璐�
+ const deliveryStatus = row.deliveryStatus;
+ if (
+ deliveryStatus !== null &&
+ deliveryStatus !== undefined &&
+ String(deliveryStatus).trim() !== ""
+ ) {
+ if (Number(deliveryStatus) === 1) return false;
+ }
+
+ // 鑾峰彇鍙戣揣鐘舵��
+ const shippingStatus = row.shippingStatus;
+
+ // 濡傛灉宸插彂璐э紙鏈夊彂璐ф棩鏈熸垨杞︾墝鍙凤級锛屼笉鑳藉啀娆″彂璐�
+ if (row.shippingDate || row.shippingCarNumber) {
+ return false;
+ }
+
+ // 鍙戣揣鐘舵�佸繀椤绘槸"寰呭彂璐�"鎴�"瀹℃牳鎷掔粷"
+ const statusStr = shippingStatus ? String(shippingStatus).trim() : "";
+ return statusStr === "寰呭彂璐�" || statusStr === "瀹℃牳鎷掔粷";
+ };
+
+ const handleBulkDelivery = async () => {
+ if (selectedRows.value.length === 0) {
+ proxy.$modal.msgWarning("璇烽�夋嫨鏁版嵁");
+ return;
+ }
+
+ // 鍙厑璁搞�愭湭鍙戣揣/瀹℃壒澶辫触銆戣繘鍏ュ彂璐ф祦绋�
+ const canDeliveryLedgers = selectedRows.value.filter(r => {
+ const status = Number(r.deliveryStatus);
+ return status === 1 || status === 3;
+ });
+ if (canDeliveryLedgers.length === 0) {
+ proxy.$modal.msgWarning("浠呮湭鍙戣揣鎴栧鎵瑰け璐ョ殑鍙拌处鍙互鍙戣揣");
+ return;
+ }
+
+ // 宸插彂璐у彴璐︼細寮圭獥鎻愰啋锛屼笉鑳藉啀娆″彂璐э紙4 瑙嗕负宸插彂璐э級
+ const shippedLedgers = selectedRows.value.filter(
+ r => Number(r.deliveryStatus) === 4
+ );
+ if (shippedLedgers.length === selectedRows.value.length) {
+ try {
+ await ElMessageBox.alert("鎵�閫夐攢鍞彴璐﹀潎宸插彂璐э紝涓嶈兘鍐嶆鍙戣揣銆�", "鎻愮ず", {
+ type: "warning",
+ confirmButtonText: "鐭ラ亾浜�",
+ });
+ } catch {
+ /* 鍏抽棴寮圭獥 */
+ }
+ return;
+ }
+ if (shippedLedgers.length > 0) {
+ try {
+ await ElMessageBox.alert(
+ "閫変腑鐨勯攢鍞彴璐︿腑鍖呭惈宸插彂璐ц褰曪紝宸插彂璐х殑涓嶈兘鍐嶆鍙戣揣锛岀郴缁熷皢浠呬负鏈彂璐у彴璐﹀鐞嗐��",
+ "鎻愮ず",
+ {
+ type: "warning",
+ confirmButtonText: "鐭ラ亾浜�",
+ }
+ );
+ } catch {
+ return;
+ }
+ }
+
+ const customerNames = selectedRows.value.map(r =>
+ String(r.customerName || "").trim()
+ );
+ const uniqueCustomers = Array.from(new Set(customerNames));
+
+ // 瀹㈡埛鍚嶇О涓嶄竴鑷翠笉鍏佽鍙戣揣
+ if (uniqueCustomers.length > 1) {
+ proxy.$modal.msgWarning("瀹㈡埛鍚嶇О涓嶄竴鑷达紝涓嶅厑璁稿彂璐�");
+ return;
+ }
+
+ // 澶氭潯涓斿鎴蜂竴鑷达細浜屾纭
+ if (selectedRows.value.length > 1) {
+ try {
+ await ElMessageBox.confirm("鏄惁纭鍚堝苟鍙戣揣锛�", "鍚堝苟鍙戣揣", {
+ confirmButtonText: "纭",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ });
+ } catch (e) {
+ proxy.$modal.msg("宸插彇娑�");
+ return;
+ }
+ }
+
+ proxy.$modal.loading("姝e湪鑾峰彇浜у搧鏁版嵁锛岃绋嶅��...");
+ try {
+ const targets = [];
+ for (const ledger of selectedRows.value) {
+ //濡傛灉宸茬粡鏄�滃鎵逛腑(2)鈥濇垨鈥滃凡鍙戣揣(4)鈥濓紝鍒欒烦杩囷紝涓嶅厑璁搁噸澶嶆搷浣�
+ const status = Number(ledger.deliveryStatus);
+ if (status === 2 || status === 4) {
+ console.warn(
+ `鍙拌处缂栧彿 ${ledger.salesContractNo} 鐘舵�佷负 ${status}锛岃烦杩囧彂璐
+ );
+ continue;
+ }
+
+ let products = [];
+ try {
+ const res = await productList({ salesLedgerId: ledger.id, type: 1 });
+ products = res?.data || [];
+ } catch (error) {
+ products = [];
+ console.error("璇锋眰鍙戠敓寮傚父", error);
+ }
+ for (const product of products) {
+ if (!canShip(product)) continue;
+ targets.push({
+ ...product,
+ salesLedgerId: product.salesLedgerId || ledger.id,
+ });
+ }
+ }
+ if (targets.length === 0) {
+ proxy.$modal.msgWarning("娌℃湁鍙彂璐х殑鏁版嵁");
+ return;
+ }
+
+ currentDeliveryRows.value = targets;
+ deliveryForm.value = { type: "璐ц溅" };
+ // 閲嶇疆瀹℃壒浜鸿妭鐐癸紙榛樿涓�涓┖鑺傜偣锛�
+ approverNodes.value = [{ id: 1, userId: null }];
+ nextApproverId = 2;
+ deliveryFormVisible.value = true;
+ } finally {
+ proxy.$modal.closeLoading();
+ }
+ };
+
+ /**
+ * 涓嬭浇鏂囦欢
+ *
+ * @param row 涓嬭浇鏂囦欢鐨勭浉鍏充俊鎭璞�
+ */
+ const fileListRef = ref(null);
+ const fileListDialogVisible = ref(false);
+ const downLoadFile = row => {
+ getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => {
+ if (fileListRef.value) {
+ fileListRef.value.open(res.salesLedgerFiles);
+ }
+ });
+ };
+
+ // 鎵撳紑鍙戣揣寮规锛堝崟鏉★級
+ const openDeliveryForm = row => {
+ // 鍙厑璁搞�愭湭鍙戣揣/瀹℃壒澶辫触銆戝彂璐э紱宸插彂璐�/瀹℃壒涓笉鍏佽
+ const status = Number(row.deliveryStatus);
+ if (status !== 1 && status !== 3) {
+ proxy.$modal.msgWarning("鍙湁鍙戣揣鐘舵�佷负鏈彂璐ф垨瀹℃壒澶辫触鐨勮褰曟墠鍙互鍙戣揣");
+ return;
+ }
+
+ currentDeliveryRows.value = [row];
+ deliveryForm.value = {
+ type: "璐ц溅",
+ };
+ // 閲嶇疆瀹℃壒浜鸿妭鐐癸紙榛樿涓�涓┖鑺傜偣锛�
+ approverNodes.value = [{ id: 1, userId: null }];
+ nextApproverId = 2;
+ deliveryFormVisible.value = true;
+ };
+
+ // 鎻愪氦鍙戣揣琛ㄥ崟
+ const submitDelivery = () => {
+ proxy.$refs["deliveryFormRef"].validate(valid => {
+ if (valid) {
+ // 瀹℃壒浜哄繀濉牎楠岋紙鎵�鏈夎妭鐐归兘瑕侀�変汉锛�
+ const hasEmptyApprover = approverNodes.value.some(node => !node.userId);
+ if (hasEmptyApprover) {
+ proxy.$modal.msgError("璇蜂负鎵�鏈夊鎵硅妭鐐归�夋嫨瀹℃壒浜猴紒");
+ return;
+ }
+ const approveUserIds = approverNodes.value
+ .map(node => node.userId)
+ .join(",");
+ // 淇濆瓨褰撳墠灞曞紑鐨勮ID锛屼互渚垮彂璐у悗閲嶆柊鍔犺浇瀛愯〃鏍兼暟鎹�
+ const currentExpandedKeys = [...expandedRowKeys.value];
+
+ const targets = currentDeliveryRows.value || [];
+ if (targets.length === 0) {
+ proxy.$modal.msgWarning("鏈�夋嫨鍙彂璐х殑鏁版嵁");
+ return;
+ }
+
+ // 鎸夊彴璐︾淮搴﹀幓閲嶏紝姣忎釜 salesLedgerId 鍙皟鐢ㄤ竴娆″彂璐ф帴鍙�
+ const uniqueLedgerIds = [
+ ...new Set(targets.map(item => item.salesLedgerId).filter(Boolean)),
+ ];
+
+ const run = async () => {
+ for (const salesLedgerId of uniqueLedgerIds) {
+ await addShippingInfo({
+ salesLedgerId,
+ type: deliveryForm.value.type,
+ approveUserIds,
+ });
+ }
+ };
+
+ run()
+ .then(() => {
+ proxy.$modal.msgSuccess("鍙戣揣鎴愬姛");
+ closeDeliveryDia();
+ // 鍒锋柊涓昏〃鏁版嵁
+ getList().then(() => {
+ // 濡傛灉涔嬪墠鏈夊睍寮�鐨勮锛岄噸鏂板姞杞借繖浜涜鐨勫瓙琛ㄦ牸鏁版嵁
+ if (currentExpandedKeys.length > 0) {
+ const loadPromises = currentExpandedKeys.map(ledgerId => {
+ return productList({ salesLedgerId: ledgerId, type: 1 }).then(
+ res => {
+ const index = tableData.value.findIndex(
+ item => item.id === ledgerId
+ );
+ if (index > -1) {
+ tableData.value[index].children = res.data;
+ }
+ }
+ );
+ });
+ Promise.all(loadPromises).then(() => {
+ expandedRowKeys.value = currentExpandedKeys;
+ });
+ }
+ });
+ })
+ .catch(() => {
+ proxy.$modal.msgError("鍙戣揣澶辫触锛岃绋嶅悗閲嶈瘯");
+ });
+ }
+ });
+ };
+
+ // 鍏抽棴鍙戣揣寮规
+ const closeDeliveryDia = () => {
+ proxy.resetForm("deliveryFormRef");
+ deliveryFormVisible.value = false;
+ currentDeliveryRows.value = [];
+ };
+ const currentFactoryName = ref("");
+ const getCurrentFactoryName = async () => {
+ let res = await userStore.getInfo();
+ currentFactoryName.value = res.user.currentFactoryName;
+ };
+ onMounted(() => {
+ getList();
+ customerList().then(res => {
+ customerOption.value = res;
+ });
+ userListNoPage().then(res => {
+ userList.value = res.data;
+ });
+ approveUserList({ approveType: 7 }).then(res => {
+ userListApprove.value = res.data;
+ });
+ getCurrentFactoryName();
+ });
</script>
<style scoped lang="scss">
+ .ml-10 {
+ margin-left: 10px;
+ }
-</style>
\ No newline at end of file
+ ::v-deep .yellow {
+ background-color: #faf0de;
+ }
+
+ ::v-deep .pink {
+ background-color: #fae1de;
+ }
+
+ ::v-deep .red {
+ background-color: #fae1de;
+ }
+
+ ::v-deep .purple {
+ background-color: #f4defa;
+ }
+
+ .other-amount-select {
+ /* 澶氶�夋爣绛惧尯鍩熷己鍒跺崟琛岋紝涓嶈杈撳叆妗嗛殢鏍囩鎹㈣鑰屾媺楂橀珮搴� */
+ :deep .el-select__tags {
+ display: flex;
+ flex-wrap: nowrap !important;
+ white-space: nowrap;
+ overflow: hidden;
+ max-height: 32px;
+ }
+ }
+
+ .table_list {
+ margin-top: unset;
+ }
+
+ .actions {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 10px;
+ }
+</style>
--
Gitblit v1.9.3