From de4ac959d99138074276563d6d4ca44d76b17705 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期三, 20 五月 2026 16:44:25 +0800
Subject: [PATCH] Merge branch 'dev_NEW_pro' into dev_天津_宝东
---
src/pages/sales/salesQuotation/edit.vue | 636 +++++++++++++++++++++++++++++++++++++++------------------
1 files changed, 436 insertions(+), 200 deletions(-)
diff --git a/src/pages/sales/salesQuotation/edit.vue b/src/pages/sales/salesQuotation/edit.vue
index 80561e5..bfcb930 100644
--- a/src/pages/sales/salesQuotation/edit.vue
+++ b/src/pages/sales/salesQuotation/edit.vue
@@ -1,124 +1,301 @@
<template>
<view class="account-detail">
- <PageHeader :title="pageTitle" @back="goBack" />
-
+ <PageHeader :title="pageTitle"
+ @back="goBack" />
<view class="form-container">
- <up-form ref="formRef" :model="form" label-width="110" input-align="right" error-message-align="right">
- <u-cell-group title="浜у搧淇℃伅" class="form-section">
+ <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="鏂板浜у搧" :disabled="isEditMode" @click="addProduct" />
+ <up-button type="primary"
+ size="small"
+ text="鏂板浜у搧"
+ @click="addProduct" />
</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 || index" class="product-card">
+ <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 class="product-header">
<text class="product-title">浜у搧 {{ index + 1 }}</text>
- <up-icon name="trash" color="#ee0a24" size="18" @click="removeProduct(index)"></up-icon>
+ <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.ProductModel"
+ 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.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.unit"
+ 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-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-input v-model="product.unitPrice"
+ type="number"
+ placeholder="璇疯緭鍏ュ崟浠�"
+ clearable
+ @blur="calculateAmount(product)" />
</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">
- <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">
+ <u-cell-group title="姹囨�讳俊鎭�"
+ class="form-section">
<up-form-item label="鎶ヤ环鎬婚">
- <up-input :model-value="formatAmount(totalAmount)" disabled placeholder="鑷姩姹囨��" />
+ <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="showProductSheet" title="閫夋嫨浜у搧" :actions="productActions" @select="onSelectProduct" @close="showProductSheet = false" />
- <up-action-sheet :show="showModelSheet" title="閫夋嫨瑙勬牸" :actions="modelActions" @select="onSelectModel" @close="showModelSheet = false" />
+ <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" />
</view>
</template>
<script setup>
- import { computed, onMounted, ref } from "vue";
+ import { computed, onMounted, onUnmounted, 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 { addOrUpdateQuotationProduct, editQuotationProduct } from "@/api/salesManagement/salesQuotationProduct";
+ import { userListNoPageByTenantId } from "@/api/system/user";
+ import {
+ addQuotation,
+ getCustomerList,
+ updateQuotation,
+ } from "@/api/salesManagement/salesQuotation";
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;
+
const form = ref({
id: undefined,
+ quotationNo: "",
+ customerId: undefined,
+ customer: "",
+ salesperson: "",
+ quotationDate: "",
+ validDate: "",
+ paymentMethod: "",
+ status: "鑽夌",
remark: "",
products: [],
+ subtotal: 0,
+ freight: 0,
+ otherFee: 0,
+ discountRate: 0,
+ discountAmount: 0,
totalAmount: 0,
});
+ 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 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 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.id,
+ }))
+ );
+ const salespersonActions = computed(() =>
+ salespersonList.value.map(item => ({
+ name: item.nickName,
+ value: item.nickName,
+ }))
+ );
+ const productActions = computed(() =>
+ productList.value.map(item => ({
+ name: item.label,
+ value: item.value,
+ label: item.label,
+ }))
+ );
const createEmptyProduct = () => ({
uid: `p_${uidSeed++}`,
- id: "",
- salesQuotationId: "",
productId: "",
product: "",
- specificationId: "",
- specification: "",
+ productModelId: "",
+ ProductModel: "",
unit: "",
- paper: "",
- paperWeight: "",
quantity: 1,
unitPrice: 0,
- printingFee: 0,
- dieCuttingFee: 0,
- grindingFee: 0,
amount: 0,
modelOptions: [],
});
@@ -127,68 +304,51 @@
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 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 calculateAmount = product => {
+ product.amount = Number(
+ (Number(product.quantity || 0) * Number(product.unitPrice || 0)).toFixed(2)
);
-
- const syncTotalAmount = () => {
form.value.totalAmount = totalAmount.value;
};
- const calculateAmount = product => {
- product.amount = Number((Number(product.quantity || 0) * Number(product.unitPrice || 0)).toFixed(2));
- syncTotalAmount();
- };
-
- const addProduct = () => {
- if (isEditMode.value) {
- uni.showToast({ title: "缂栬緫妯″紡涓嬩笉鍏佽鏂板浜у搧", icon: "none" });
- return;
- }
- form.value.products.push(createEmptyProduct());
- };
-
+ const addProduct = () => form.value.products.push(createEmptyProduct());
const removeProduct = index => {
form.value.products.splice(index, 1);
- syncTotalAmount();
+ form.value.totalAmount = totalAmount.value;
};
const fetchModelOptions = async (productId, product) => {
- const rows = await modelList({ id: productId }).catch(() => []);
- product.modelOptions = Array.isArray(rows) ? rows : [];
+ try {
+ const res = await modelList({ id: productId });
+ const rows = res?.data?.records || res?.data || res?.records || res || [];
+ product.modelOptions = Array.isArray(rows) ? rows : [];
+ } catch (error) {
+ console.error("鑾峰彇瑙勬牸鍨嬪彿澶辫触:", error);
+ product.modelOptions = [];
+ }
};
const openProductPicker = index => {
currentProductIndex.value = index;
showProductSheet.value = true;
};
-
const openModelPicker = index => {
currentProductIndex.value = index;
const current = form.value.products[index];
@@ -196,70 +356,122 @@
uni.showToast({ title: "璇峰厛閫夋嫨浜у搧", icon: "none" });
return;
}
- modelActions.value = (current.modelOptions || []).map(item => ({ name: item.model, value: item.id, unit: item.unit }));
+ modelActions.value = (current.modelOptions || []).map(item => ({
+ name: item.model || item.specification,
+ 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.customerId = action.value;
+ form.value.customer = action.name;
+ showCustomerSheet.value = false;
+ };
+ const onSelectSalesperson = action => {
+ form.value.salesperson = action.value;
+ showSalespersonSheet.value = false;
+ };
const onSelectProduct = action => {
const current = form.value.products[currentProductIndex.value];
if (!current) return;
current.productId = action.value;
current.product = action.label;
- current.specificationId = "";
- current.specification = "";
+ current.productModelId = "";
+ current.ProductModel = "";
current.unit = "";
current.modelOptions = [];
showProductSheet.value = false;
fetchModelOptions(action.value, current);
};
-
const onSelectModel = action => {
const current = form.value.products[currentProductIndex.value];
if (!current) return;
- current.specificationId = action.value;
- current.specification = action.name;
+ current.productModelId = action.value;
+ current.ProductModel = action.name;
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 fetchProductOptions = async () => {
- const productTree = await productTreeList().catch(() => []);
- productList.value = flattenProductTree(Array.isArray(productTree) ? productTree : productTree?.data || []);
+ 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 : [];
+ productList.value = flattenProductTree(
+ Array.isArray(productTree) ? productTree : productTree?.data || []
+ );
+ };
+
+ // 鏍规嵁鍚嶇О鍙嶆煡鑺傜偣 id锛屼究浜庝粎瀛樺悕绉版椂鐨勫弽鏄�
+ const 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 normalizeProductRows = async rows => {
const normalized = await Promise.all(
(Array.isArray(rows) ? rows : []).map(async item => {
+ const productName = item.product || item.productName || "";
+ // 浼樺厛鐢� productId锛涘鏋滃彧鏈夊悕绉帮紝灏濊瘯鍙嶆煡 id 浠ヤ究閫夋嫨鍣ㄥ弽鏄�
+ let resolvedProductId =
+ item.productId ||
+ findNodeIdByLabel(productList.value, productName) ||
+ "";
+
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 || "",
+ productId: resolvedProductId,
+ product: productName,
+ productModelId: item.productModelId || "",
+ ProductModel: item.ProductModel || 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)),
+ amount: Number(item.amount || 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 || "";
+ // 濡傛灉娌℃湁 productModelId 浣嗘湁 ProductModel 鍚嶇О锛屽皾璇曚粠 modelOptions 涓尮閰� ID
+ if (!row.productModelId && row.ProductModel) {
+ const foundModel = row.modelOptions.find(
+ m =>
+ m.model === row.ProductModel ||
+ m.specification === row.ProductModel
+ );
+ if (foundModel) {
+ row.productModelId = foundModel.id;
+ // 缁熶竴浣跨敤 modelOptions 涓殑瀛楁
+ row.ProductModel =
+ foundModel.model || foundModel.specification || row.ProductModel;
+ row.unit = foundModel.unit || row.unit;
}
}
}
@@ -269,26 +481,41 @@
form.value.products = normalized;
};
- const loadEditFromStorage = async () => {
+ const loadDetail = async () => {
if (!quotationId.value) return;
- 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 cachedData = uni.getStorageSync("salesQuotationDetail");
+ if (
+ cachedData &&
+ (cachedData.id === quotationId.value ||
+ cachedData.id === Number(quotationId.value))
+ ) {
+ const data = cachedData;
+ form.value = {
+ ...form.value,
+ id: data.id,
+ quotationNo: data.quotationNo || "",
+ customerId: data.customerId,
+ customer: data.customer || "",
+ salesperson: data.salesperson || "",
+ quotationDate: data.quotationDate || "",
+ validDate: data.validDate || "",
+ paymentMethod: data.paymentMethod || "",
+ status: data.status || "鑽夌",
+ remark: data.remark || "",
+ subtotal: data.subtotal || 0,
+ freight: data.freight || 0,
+ otherFee: data.otherFee || 0,
+ discountRate: data.discountRate || 0,
+ discountAmount: data.discountAmount || 0,
+ totalAmount: data.totalAmount || 0,
+ };
+ await normalizeProductRows(data.products || []);
+ form.value.totalAmount = totalAmount.value;
+ } else {
+ console.warn("鏈壘鍒扮紦瀛樼殑鎶ヤ环鍗曡鎯呮暟鎹�");
+ }
};
const validateProducts = () => {
@@ -296,7 +523,14 @@
uni.showToast({ title: "璇疯嚦灏戞坊鍔犱竴涓骇鍝�", icon: "none" });
return false;
}
- const invalid = form.value.products.some(item => !item.productId || !item.specificationId || !item.unit || !Number(item.unitPrice || 0));
+ const invalid = form.value.products.some(
+ item =>
+ !item.productId ||
+ !item.productModelId ||
+ !item.unit ||
+ !Number(item.quantity) ||
+ !Number(item.unitPrice)
+ );
if (invalid) {
uni.showToast({ title: "璇峰畬鍠勪骇鍝佷俊鎭�", icon: "none" });
return false;
@@ -304,56 +538,30 @@
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 () => {
- if (!validateProducts()) return;
-
+ const valid = await formRef.value.validate().catch(() => false);
+ if (!valid || !validateProducts()) return;
loading.value = true;
- 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)
+ // 鍚屾鏈�鏂扮殑鎬婚
+ form.value.totalAmount = totalAmount.value;
+ form.value.subtotal = totalAmount.value;
+
+ const payload = {
+ ...form.value,
+ products: form.value.products.map(item => ({
+ productId: item.productId,
+ product: item.product,
+ productModelId: item.productModelId,
+ ProductModel: item.ProductModel,
+ 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)
.then(() => {
uni.showToast({ title: "淇濆瓨鎴愬姛", icon: "success" });
setTimeout(() => uni.navigateBack(), 300);
@@ -371,21 +579,56 @@
quotationId.value = options.id;
form.value.id = options.id;
} else {
- form.value.products = [];
+ const today = formatDateToYMD(Date.now());
+ form.value.quotationDate = today;
+ form.value.validDate = today;
}
});
onMounted(async () => {
- await fetchProductOptions();
- if (quotationId.value) await loadEditFromStorage();
+ await fetchBaseOptions();
+ if (quotationId.value) {
+ await loadDetail();
+ }
});
+
+ onUnmounted(() => {});
</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 {
@@ -435,13 +678,6 @@
padding: 16px 12px;
color: #999;
font-size: 14px;
- }
-
- .summary-tip {
- padding: 0 24rpx 24rpx;
- color: #909399;
- font-size: 12px;
- line-height: 1.6;
}
:deep(.u-cell-group__title) {
--
Gitblit v1.9.3