From 36c8ae70cae3de90e642b080553abe70d3345c74 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 27 四月 2026 13:20:16 +0800
Subject: [PATCH] 天津宝东app 1.部署修改 2.按照web端逻辑修改销售报价和客户档案的逻辑
---
src/pages/sales/salesQuotation/edit.vue | 551 +++++++++++++++++++-----------------------------------
1 files changed, 196 insertions(+), 355 deletions(-)
diff --git a/src/pages/sales/salesQuotation/edit.vue b/src/pages/sales/salesQuotation/edit.vue
index 940a8d9..80561e5 100644
--- a/src/pages/sales/salesQuotation/edit.vue
+++ b/src/pages/sales/salesQuotation/edit.vue
@@ -3,246 +3,122 @@
<PageHeader :title="pageTitle" @back="goBack" />
<view class="form-container">
- <up-form
- ref="formRef"
- :model="form"
- :rules="rules"
- label-width="110"
- input-align="right"
- error-message-align="right"
- >
- <u-cell-group title="鍩虹淇℃伅" class="form-section">
- <up-form-item label="瀹㈡埛鍚嶇О" prop="customer" required>
- <up-input v-model="form.customer" placeholder="璇烽�夋嫨瀹㈡埛" readonly @click="showCustomerSheet = true" />
- <template #right>
- <up-icon name="arrow-right" @click="showCustomerSheet = true"></up-icon>
- </template>
- </up-form-item>
- <up-form-item label="涓氬姟鍛�" prop="salesperson" required>
- <up-input
- v-model="form.salesperson"
- placeholder="璇烽�夋嫨涓氬姟鍛�"
- readonly
- @click="showSalespersonSheet = true"
- />
- <template #right>
- <up-icon name="arrow-right" @click="showSalespersonSheet = true"></up-icon>
- </template>
- </up-form-item>
- <up-form-item label="鎶ヤ环鏃ユ湡" prop="quotationDate" required>
- <up-input
- v-model="form.quotationDate"
- placeholder="璇烽�夋嫨鎶ヤ环鏃ユ湡"
- readonly
- @click="showQuotationDatePicker = true"
- />
- <template #right>
- <up-icon name="arrow-right" @click="showQuotationDatePicker = true"></up-icon>
- </template>
- </up-form-item>
- <up-form-item label="鏈夋晥鏈熻嚦" prop="validDate" required>
- <up-input
- v-model="form.validDate"
- placeholder="璇烽�夋嫨鏈夋晥鏈�"
- readonly
- @click="showValidDatePicker = true"
- />
- <template #right>
- <up-icon name="arrow-right" @click="showValidDatePicker = true"></up-icon>
- </template>
- </up-form-item>
- <up-form-item label="浠樻鏂瑰紡" prop="paymentMethod" required>
- <up-input v-model="form.paymentMethod" placeholder="璇疯緭鍏ヤ粯娆炬柟寮�" clearable />
- </up-form-item>
- <up-form-item label="澶囨敞" prop="remark">
- <up-textarea v-model="form.remark" placeholder="璇疯緭鍏ュ娉�" auto-height />
- </up-form-item>
- </u-cell-group>
-
- <u-cell-group title="瀹℃壒鑺傜偣" class="form-section">
- <view class="section-tools">
- <up-button type="primary" size="small" text="鏂板鑺傜偣" @click="addApproverNode" />
- </view>
- <view v-if="salespersonList.length === 0" class="empty-text">
- <text>鏆傛棤鍙�夊鎵逛汉锛岃妫�鏌ョ敤鎴锋暟鎹�</text>
- </view>
- <view class="node-list">
- <view v-for="(node, index) in approverNodes" :key="node.id" class="node-card">
- <view class="node-top">
- <text class="node-title">瀹℃壒鑺傜偣 {{ index + 1 }}</text>
- <up-icon
- v-if="approverNodes.length > 1"
- name="trash"
- color="#ee0a24"
- size="18"
- @click="removeApproverNode(index)"
- ></up-icon>
- </view>
- <view class="picker-field" @click="openApproverPicker(index)">
- <up-input :model-value="node.nickName || ''" placeholder="璇烽�夋嫨瀹℃壒浜�" readonly disabled />
- <up-icon name="arrow-right" color="#909399" size="16"></up-icon>
- </view>
- </view>
- </view>
- </u-cell-group>
-
+ <up-form ref="formRef" :model="form" label-width="110" input-align="right" error-message-align="right">
<u-cell-group title="浜у搧淇℃伅" class="form-section">
<view class="section-tools">
- <up-button type="primary" size="small" text="鏂板浜у搧" @click="addProduct" />
+ <up-button type="primary" size="small" text="鏂板浜у搧" :disabled="isEditMode" @click="addProduct" />
</view>
- <view v-if="form.products.length === 0" class="empty-text">
- <text>鏆傛棤浜у搧锛岃鍏堟坊鍔犱骇鍝�</text>
- </view>
+ <view v-if="form.products.length === 0" class="empty-text"><text>鏆傛棤浜у搧</text></view>
<view v-else class="product-list">
- <view v-for="(product, index) in form.products" :key="product.uid" class="product-card">
+ <view v-for="(product, index) in form.products" :key="product.uid || index" class="product-card">
<view class="product-header">
<text class="product-title">浜у搧 {{ index + 1 }}</text>
<up-icon name="trash" color="#ee0a24" size="18" @click="removeProduct(index)"></up-icon>
</view>
<up-divider></up-divider>
<view class="product-body">
- <up-form-item label="浜у搧鍚嶇О">
- <up-input
- v-model="product.product"
- placeholder="璇烽�夋嫨浜у搧"
- readonly
- @click="openProductPicker(index)"
- />
- <template #right>
- <up-icon name="arrow-right" @click="openProductPicker(index)"></up-icon>
- </template>
+ <up-form-item label="浜у搧">
+ <up-input v-model="product.product" placeholder="璇烽�夋嫨浜у搧" readonly @click="openProductPicker(index)" />
+ <template #right><up-icon name="arrow-right" @click="openProductPicker(index)"></up-icon></template>
</up-form-item>
- <up-form-item label="瑙勬牸鍨嬪彿">
- <up-input
- v-model="product.specification"
- placeholder="璇烽�夋嫨瑙勬牸鍨嬪彿"
- readonly
- @click="openModelPicker(index)"
- />
- <template #right>
- <up-icon name="arrow-right" @click="openModelPicker(index)"></up-icon>
- </template>
+ <up-form-item label="瑙勬牸">
+ <up-input v-model="product.specification" placeholder="璇烽�夋嫨瑙勬牸" readonly @click="openModelPicker(index)" />
+ <template #right><up-icon name="arrow-right" @click="openModelPicker(index)"></up-icon></template>
</up-form-item>
- <up-form-item label="鍗曚綅">
- <up-input v-model="product.unit" placeholder="璇疯緭鍏ュ崟浣�" clearable />
- </up-form-item>
+ <up-form-item label="鍗曚綅"><up-input v-model="product.unit" placeholder="璇疯緭鍏ュ崟浣�" clearable /></up-form-item>
+ <up-form-item label="绾稿紶"><up-input v-model="product.paper" placeholder="璇疯緭鍏ョ焊寮�" clearable /></up-form-item>
+ <up-form-item label="瀹氶噺"><up-input v-model="product.paperWeight" placeholder="璇疯緭鍏ュ畾閲�" clearable /></up-form-item>
<up-form-item label="鏁伴噺">
- <up-input
- v-model="product.quantity"
- type="number"
- placeholder="璇疯緭鍏ユ暟閲�"
- clearable
- @blur="calculateAmount(product)"
- />
+ <up-input v-model="product.quantity" type="number" placeholder="璇疯緭鍏ユ暟閲�" clearable @blur="calculateAmount(product)" />
</up-form-item>
<up-form-item label="鍗曚环">
- <up-input
- v-model="product.unitPrice"
- type="number"
- placeholder="璇疯緭鍏ュ崟浠�"
- clearable
- @blur="calculateAmount(product)"
- />
+ <up-input v-model="product.unitPrice" type="number" placeholder="璇疯緭鍏ュ崟浠�" clearable @blur="calculateAmount(product)" />
+ </up-form-item>
+ <up-form-item label="鍗扮増璐�">
+ <up-input v-model="product.printingFee" type="number" placeholder="璇疯緭鍏ュ嵃鐗堣垂" clearable @blur="syncTotalAmount" />
+ </up-form-item>
+ <up-form-item label="鍒�鐗堣垂">
+ <up-input v-model="product.dieCuttingFee" type="number" placeholder="璇疯緭鍏ュ垁鐗堣垂" clearable @blur="syncTotalAmount" />
+ </up-form-item>
+ <up-form-item label="纾ㄥ叿璐�">
+ <up-input v-model="product.grindingFee" type="number" placeholder="璇疯緭鍏ョ(鍏疯垂" clearable @blur="syncTotalAmount" />
</up-form-item>
<up-form-item label="閲戦">
- <up-input :model-value="formatAmount(product.amount)" disabled placeholder="鑷姩璁$畻" />
+ <up-input :model-value="formatAmount(product.amount)" disabled placeholder="鑷姩璁$畻锛堟暟閲�*鍗曚环锛�" />
</up-form-item>
</view>
</view>
</view>
</u-cell-group>
- <u-cell-group title="姹囨�讳俊鎭�" class="form-section">
+ <u-cell-group title="澶囨敞淇℃伅" class="form-section">
+ <up-form-item label="澶囨敞">
+ <up-textarea v-model="form.remark" placeholder="璇疯緭鍏ュ娉紙閫夊~锛�" auto-height />
+ </up-form-item>
+ </u-cell-group>
+
+ <u-cell-group title="姹囨��" class="form-section">
<up-form-item label="鎶ヤ环鎬婚">
<up-input :model-value="formatAmount(totalAmount)" disabled placeholder="鑷姩姹囨��" />
</up-form-item>
+ <view class="summary-tip">鎬婚瑙勫垯锛氬崟浠� + 鍗扮増璐� + 鍒�鐗堣垂 + 纾ㄥ叿璐癸紙鎸変骇鍝侀�愯姹傚拰锛�</view>
</u-cell-group>
</up-form>
</view>
<FooterButtons :loading="loading" confirmText="淇濆瓨" @cancel="goBack" @confirm="handleSubmit" />
- <up-action-sheet :show="showCustomerSheet" title="閫夋嫨瀹㈡埛" :actions="customerActions" @select="onSelectCustomer" @close="showCustomerSheet = false" />
- <up-action-sheet :show="showSalespersonSheet" title="閫夋嫨涓氬姟鍛�" :actions="salespersonActions" @select="onSelectSalesperson" @close="showSalespersonSheet = false" />
<up-action-sheet :show="showProductSheet" title="閫夋嫨浜у搧" :actions="productActions" @select="onSelectProduct" @close="showProductSheet = false" />
- <up-action-sheet :show="showModelSheet" title="閫夋嫨瑙勬牸鍨嬪彿" :actions="modelActions" @select="onSelectModel" @close="showModelSheet = false" />
- <up-datetime-picker :show="showQuotationDatePicker" v-model="quotationDateValue" mode="date" @confirm="onQuotationDateConfirm" @cancel="showQuotationDatePicker = false" />
- <up-datetime-picker :show="showValidDatePicker" v-model="validDateValue" mode="date" @confirm="onValidDateConfirm" @cancel="showValidDatePicker = false" />
+ <up-action-sheet :show="showModelSheet" title="閫夋嫨瑙勬牸" :actions="modelActions" @select="onSelectModel" @close="showModelSheet = false" />
</view>
</template>
<script setup>
- import { computed, onMounted, onUnmounted, ref } from "vue";
+ import { computed, onMounted, ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import FooterButtons from "@/components/FooterButtons.vue";
import PageHeader from "@/components/PageHeader.vue";
- import { formatDateToYMD } from "@/utils/ruoyi";
import { modelList, productTreeList } from "@/api/basicData/product";
- import { userListNoPageByTenantId } from "@/api/system/user";
- import { addQuotation, getCustomerList, getQuotationDetail, updateQuotation } from "@/api/salesManagement/salesQuotation";
+ import { addOrUpdateQuotationProduct, editQuotationProduct } from "@/api/salesManagement/salesQuotationProduct";
const formRef = ref();
const loading = ref(false);
const quotationId = ref("");
- const showCustomerSheet = ref(false);
- const showSalespersonSheet = ref(false);
const showProductSheet = ref(false);
const showModelSheet = ref(false);
- const showQuotationDatePicker = ref(false);
- const showValidDatePicker = ref(false);
- const quotationDateValue = ref(Date.now());
- const validDateValue = ref(Date.now());
const currentProductIndex = ref(-1);
- const customerList = ref([]);
- const salespersonList = ref([]);
const productList = ref([]);
const modelActions = ref([]);
let uidSeed = 1;
- let nextApproverId = 2;
-
const form = ref({
id: undefined,
- quotationNo: "",
- customer: "",
- salesperson: "",
- quotationDate: "",
- validDate: "",
- paymentMethod: "",
- status: "寰呭鎵�",
remark: "",
- approveUserIds: "",
products: [],
totalAmount: 0,
});
- const approverNodes = ref([{ id: 1, userId: "", nickName: "" }]);
-
- const rules = {
- customer: [{ required: true, message: "璇烽�夋嫨瀹㈡埛", trigger: "change" }],
- salesperson: [{ required: true, message: "璇烽�夋嫨涓氬姟鍛�", trigger: "change" }],
- quotationDate: [{ required: true, message: "璇烽�夋嫨鎶ヤ环鏃ユ湡", trigger: "change" }],
- validDate: [{ required: true, message: "璇烽�夋嫨鏈夋晥鏈�", trigger: "change" }],
- paymentMethod: [{ required: true, message: "璇疯緭鍏ヤ粯娆炬柟寮�", trigger: "blur" }],
- };
-
const pageTitle = computed(() => (quotationId.value ? "缂栬緫鎶ヤ环" : "鏂板鎶ヤ环"));
- const totalAmount = computed(() =>
- Number((form.value.products || []).reduce((sum, item) => sum + Number(item.amount || 0), 0).toFixed(2))
- );
- const customerActions = computed(() => customerList.value.map(item => ({ name: item.customerName, value: item.customerName })));
- const salespersonActions = computed(() => salespersonList.value.map(item => ({ name: item.nickName, value: item.nickName })));
+ const isEditMode = computed(() => Boolean(quotationId.value));
const productActions = computed(() => productList.value.map(item => ({ name: item.label, value: item.value, label: item.label })));
+ const totalAmount = computed(() => calcTotalAmountFromProducts(form.value.products));
const createEmptyProduct = () => ({
uid: `p_${uidSeed++}`,
+ id: "",
+ salesQuotationId: "",
productId: "",
product: "",
specificationId: "",
specification: "",
unit: "",
+ paper: "",
+ paperWeight: "",
quantity: 1,
unitPrice: 0,
+ printingFee: 0,
+ dieCuttingFee: 0,
+ grindingFee: 0,
amount: 0,
modelOptions: [],
});
@@ -251,37 +127,56 @@
const result = [];
const walk = list => {
(list || []).forEach(item => {
- if (item.children && item.children.length) {
- walk(item.children);
- } else {
- result.push({ label: item.label || item.productName || "", value: item.id || item.value });
- }
+ if (item.children && item.children.length) walk(item.children);
+ else result.push({ label: item.label || item.productName || "", value: item.id || item.value });
});
};
walk(nodes);
return result;
};
+ const findProductIdByLabel = label => {
+ if (!label) return "";
+ const hit = (productList.value || []).find(item => item.label === label);
+ return hit?.value || "";
+ };
+
const formatAmount = amount => `楼${Number(amount || 0).toFixed(2)}`;
const goBack = () => uni.navigateBack();
- const calculateAmount = product => {
- product.amount = Number((Number(product.quantity || 0) * Number(product.unitPrice || 0)).toFixed(2));
+ const calcTotalAmountFromProducts = products =>
+ Number(
+ (products || [])
+ .reduce((sum, item) => {
+ const unitPrice = Number(item?.unitPrice || 0);
+ const printingFee = Number(item?.printingFee || 0);
+ const dieCuttingFee = Number(item?.dieCuttingFee || 0);
+ const grindingFee = Number(item?.grindingFee || 0);
+ return sum + unitPrice + printingFee + dieCuttingFee + grindingFee;
+ }, 0)
+ .toFixed(2)
+ );
+
+ const syncTotalAmount = () => {
form.value.totalAmount = totalAmount.value;
};
- const addApproverNode = () => approverNodes.value.push({ id: nextApproverId++, userId: "", nickName: "" });
- const removeApproverNode = index => approverNodes.value.splice(index, 1);
- const openApproverPicker = index => {
- uni.setStorageSync("stepIndex", index);
- uni.navigateTo({
- url: "/pages/cooperativeOffice/collaborativeApproval/contactSelect",
- });
+ const calculateAmount = product => {
+ product.amount = Number((Number(product.quantity || 0) * Number(product.unitPrice || 0)).toFixed(2));
+ syncTotalAmount();
};
- const addProduct = () => form.value.products.push(createEmptyProduct());
+
+ const addProduct = () => {
+ if (isEditMode.value) {
+ uni.showToast({ title: "缂栬緫妯″紡涓嬩笉鍏佽鏂板浜у搧", icon: "none" });
+ return;
+ }
+ form.value.products.push(createEmptyProduct());
+ };
+
const removeProduct = index => {
form.value.products.splice(index, 1);
- form.value.totalAmount = totalAmount.value;
+ syncTotalAmount();
};
const fetchModelOptions = async (productId, product) => {
@@ -293,6 +188,7 @@
currentProductIndex.value = index;
showProductSheet.value = true;
};
+
const openModelPicker = index => {
currentProductIndex.value = index;
const current = form.value.products[index];
@@ -302,27 +198,12 @@
}
modelActions.value = (current.modelOptions || []).map(item => ({ name: item.model, value: item.id, unit: item.unit }));
if (!modelActions.value.length) {
- uni.showToast({ title: "鏆傛棤瑙勬牸鍨嬪彿", icon: "none" });
+ uni.showToast({ title: "鏆傛棤瑙勬牸鏁版嵁", icon: "none" });
return;
}
showModelSheet.value = true;
};
- const onSelectCustomer = action => {
- form.value.customer = action.value;
- showCustomerSheet.value = false;
- };
- const onSelectSalesperson = action => {
- form.value.salesperson = action.value;
- showSalespersonSheet.value = false;
- };
- const onSelectApprover = data => {
- const { stepIndex, contact } = data || {};
- if (stepIndex === undefined || !contact) return;
- if (!approverNodes.value[stepIndex]) return;
- approverNodes.value[stepIndex].userId = contact.userId;
- approverNodes.value[stepIndex].nickName = contact.nickName;
- };
const onSelectProduct = action => {
const current = form.value.products[currentProductIndex.value];
if (!current) return;
@@ -335,6 +216,7 @@
showProductSheet.value = false;
fetchModelOptions(action.value, current);
};
+
const onSelectModel = action => {
const current = form.value.products[currentProductIndex.value];
if (!current) return;
@@ -343,81 +225,70 @@
current.unit = action.unit || current.unit;
showModelSheet.value = false;
};
- const onQuotationDateConfirm = e => {
- form.value.quotationDate = formatDateToYMD(e.value);
- showQuotationDatePicker.value = false;
- };
- const onValidDateConfirm = e => {
- form.value.validDate = formatDateToYMD(e.value);
- showValidDatePicker.value = false;
- };
- const fetchBaseOptions = async () => {
- const [customers, users, productTree] = await Promise.all([
- getCustomerList({ current: -1, size: -1 }).catch(() => ({})),
- userListNoPageByTenantId().catch(() => ({})),
- productTreeList().catch(() => []),
- ]);
- customerList.value = customers?.data?.records || customers?.records || [];
- const userRows = users?.data || [];
- salespersonList.value = Array.isArray(userRows) ? userRows : [];
+ const fetchProductOptions = async () => {
+ const productTree = await productTreeList().catch(() => []);
productList.value = flattenProductTree(Array.isArray(productTree) ? productTree : productTree?.data || []);
};
const normalizeProductRows = async rows => {
- const normalized = await Promise.all((Array.isArray(rows) ? rows : []).map(async item => {
- const row = {
- uid: `p_${uidSeed++}`,
- productId: item.productId || "",
- product: item.product || item.productName || "",
- specificationId: item.specificationId || "",
- specification: item.specification || "",
- unit: item.unit || "",
- quantity: Number(item.quantity || 1),
- unitPrice: Number(item.unitPrice || 0),
- amount: Number(item.amount || 0),
- modelOptions: [],
- };
- if (row.productId) await fetchModelOptions(row.productId, row);
- return row;
- }));
+ const normalized = await Promise.all(
+ (Array.isArray(rows) ? rows : []).map(async item => {
+ const row = {
+ uid: `p_${uidSeed++}`,
+ id: item.id || "",
+ salesQuotationId: item.salesQuotationId || "",
+ productId: item.productId || "",
+ product: item.product || item.productName || "",
+ specificationId: item.specificationId || "",
+ specification: item.specification || "",
+ unit: item.unit || "",
+ paper: item.paper || "",
+ paperWeight: item.paperWeight || "",
+ quantity: Number(item.quantity || 1),
+ unitPrice: Number(item.unitPrice || 0),
+ printingFee: Number(item.printingFee || 0),
+ dieCuttingFee: Number(item.dieCuttingFee || 0),
+ grindingFee: Number(item.grindingFee || 0),
+ amount: Number(item.amount || Number(item.quantity || 0) * Number(item.unitPrice || 0)),
+ modelOptions: [],
+ };
+ if (row.productId) {
+ await fetchModelOptions(row.productId, row);
+ if (!row.specificationId && row.specification) {
+ const matchedModel = (row.modelOptions || []).find(model => model.model === row.specification);
+ if (matchedModel) {
+ row.specificationId = matchedModel.id;
+ if (!row.unit) row.unit = matchedModel.unit || "";
+ }
+ }
+ }
+ return row;
+ })
+ );
form.value.products = normalized;
};
- const loadDetail = async () => {
+ const loadEditFromStorage = async () => {
if (!quotationId.value) return;
- uni.showLoading({ title: "鍔犺浇涓�...", mask: true });
- try {
- const res = await getQuotationDetail({ id: quotationId.value });
- const data = res?.data || {};
- form.value = {
- ...form.value,
- id: data.id,
- quotationNo: data.quotationNo || "",
- customer: data.customer || "",
- salesperson: data.salesperson || "",
- quotationDate: data.quotationDate || "",
- validDate: data.validDate || "",
- paymentMethod: data.paymentMethod || "",
- status: data.status || "寰呭鎵�",
- remark: data.remark || "",
- };
- await normalizeProductRows(data.products || []);
- if (data.approveUserIds) {
- const ids = String(data.approveUserIds).split(",").map(item => item.trim()).filter(Boolean);
- approverNodes.value = ids.map((userId, index) => ({
- id: index + 1,
- userId,
- nickName: salespersonList.value.find(item => String(item.userId) === String(userId))?.nickName || "",
- }));
- nextApproverId = approverNodes.value.length + 1;
- }
- form.value.totalAmount = totalAmount.value;
- } catch {
- uni.showToast({ title: "鑾峰彇璇︽儏澶辫触", icon: "error" });
- } finally {
- uni.hideLoading();
- }
+ const cached = uni.getStorageSync("salesQuotationEdit");
+ if (!cached || typeof cached !== "object") return;
+ if (cached.id && String(cached.id) !== String(quotationId.value)) return;
+
+ const data = cached;
+ form.value = {
+ ...form.value,
+ id: data.id || form.value.id,
+ remark: data.remark || "",
+ };
+
+ const rows = Array.isArray(data.products) && data.products.length ? data.products : [data];
+ const normalizedRows = rows.map(item => ({
+ ...item,
+ productId: item.productId || findProductIdByLabel(item.product || item.productName || ""),
+ }));
+ await normalizeProductRows(normalizedRows);
+ syncTotalAmount();
};
const validateProducts = () => {
@@ -425,42 +296,64 @@
uni.showToast({ title: "璇疯嚦灏戞坊鍔犱竴涓骇鍝�", icon: "none" });
return false;
}
- const invalid = form.value.products.some(item => !item.productId || !item.specificationId || !item.unit || !Number(item.quantity) || !Number(item.unitPrice));
+ const invalid = form.value.products.some(item => !item.productId || !item.specificationId || !item.unit || !Number(item.unitPrice || 0));
if (invalid) {
uni.showToast({ title: "璇峰畬鍠勪骇鍝佷俊鎭�", icon: "none" });
return false;
}
return true;
};
- const validateApprovers = () => {
- if (approverNodes.value.some(item => !item.userId)) {
- uni.showToast({ title: "璇烽�夋嫨瀹℃壒浜�", icon: "none" });
- return false;
- }
- return true;
+
+ const buildProductPayload = item => {
+ const quantity = Number(item?.quantity || 0);
+ const unitPrice = Number(item?.unitPrice || 0);
+ const printingFee = Number(item?.printingFee || 0);
+ const dieCuttingFee = Number(item?.dieCuttingFee || 0);
+ const grindingFee = Number(item?.grindingFee || 0);
+ return {
+ id: item?.id || undefined,
+ salesQuotationId: item?.salesQuotationId || null,
+ product: item?.product || "",
+ specification: item?.specification || "",
+ unit: item?.unit || "",
+ paper: item?.paper || "",
+ paperWeight: item?.paperWeight || "",
+ unitPrice,
+ printingFee,
+ dieCuttingFee,
+ grindingFee,
+ quantity,
+ amount: Number(item?.amount ?? quantity * unitPrice),
+ remark: form.value.remark || "",
+ };
};
const handleSubmit = async () => {
- const valid = await formRef.value.validate().catch(() => false);
- if (!valid || !validateApprovers() || !validateProducts()) return;
+ if (!validateProducts()) return;
+
loading.value = true;
- const payload = {
- ...form.value,
- approveUserIds: approverNodes.value.map(item => item.userId).join(","),
- totalAmount: totalAmount.value,
- products: form.value.products.map(item => ({
- productId: item.productId,
- product: item.product,
- specificationId: item.specificationId,
- specification: item.specification,
- quantity: Number(item.quantity || 0),
- unit: item.unit,
- unitPrice: Number(item.unitPrice || 0),
- amount: Number(item.amount || 0),
- })),
- };
- const action = quotationId.value ? updateQuotation : addQuotation;
- action(payload)
+ if (quotationId.value) {
+ const editingItem = form.value.products[0] || {};
+ const payload = buildProductPayload({
+ ...editingItem,
+ id: editingItem.id || quotationId.value,
+ });
+ editQuotationProduct(payload)
+ .then(() => {
+ uni.showToast({ title: "淇濆瓨鎴愬姛", icon: "success" });
+ setTimeout(() => uni.navigateBack(), 300);
+ })
+ .catch(() => {
+ uni.showToast({ title: "淇濆瓨澶辫触", icon: "error" });
+ })
+ .finally(() => {
+ loading.value = false;
+ });
+ return;
+ }
+
+ const payloadList = form.value.products.map(item => buildProductPayload(item));
+ addOrUpdateQuotationProduct(payloadList)
.then(() => {
uni.showToast({ title: "淇濆瓨鎴愬姛", icon: "success" });
setTimeout(() => uni.navigateBack(), 300);
@@ -478,60 +371,21 @@
quotationId.value = options.id;
form.value.id = options.id;
} else {
- const today = formatDateToYMD(Date.now());
- form.value.quotationDate = today;
- form.value.validDate = today;
+ form.value.products = [];
}
});
onMounted(async () => {
- await fetchBaseOptions();
- uni.$on("selectContact", onSelectApprover);
- if (quotationId.value) {
- await loadDetail();
- }
- });
-
- onUnmounted(() => {
- uni.$off("selectContact", onSelectApprover);
- uni.removeStorageSync("stepIndex");
+ await fetchProductOptions();
+ if (quotationId.value) await loadEditFromStorage();
});
</script>
<style scoped lang="scss">
@import "@/static/scss/form-common.scss";
- .account-detail {
- min-height: 100vh;
- background: #f8f9fa;
- padding-bottom: 100px;
- }
-
.form-container {
padding: 12px 12px 0;
- }
-
- .hero-card {
- margin-bottom: 12px;
- padding: 18px 18px 16px;
- border-radius: 16px;
- background: linear-gradient(135deg, #eef6ff 0%, #ffffff 100%);
- box-shadow: 0 6px 18px rgba(41, 121, 255, 0.08);
- }
-
- .hero-title {
- display: block;
- font-size: 18px;
- font-weight: 600;
- color: #1f2d3d;
- margin-bottom: 6px;
- }
-
- .hero-desc {
- display: block;
- font-size: 13px;
- line-height: 1.6;
- color: #7a8599;
}
.form-section {
@@ -547,7 +401,6 @@
padding: 12px 12px 0;
}
- .node-list,
.product-list {
padding: 12px;
display: flex;
@@ -555,31 +408,12 @@
gap: 12px;
}
- .node-card {
- background: #f8fbff;
- border-radius: 12px;
- padding: 12px;
- border: 1px solid #e6eef8;
- }
-
- .picker-field {
- display: flex;
- align-items: center;
- gap: 8px;
- }
-
- .picker-field :deep(.u-input) {
- flex: 1;
- }
-
- .node-top,
.product-header {
display: flex;
align-items: center;
justify-content: space-between;
}
- .node-title,
.product-title {
font-size: 14px;
font-weight: 600;
@@ -603,6 +437,13 @@
font-size: 14px;
}
+ .summary-tip {
+ padding: 0 24rpx 24rpx;
+ color: #909399;
+ font-size: 12px;
+ line-height: 1.6;
+ }
+
:deep(.u-cell-group__title) {
padding: 14px 18px 10px !important;
font-size: 15px !important;
--
Gitblit v1.9.3