<template>
|
<view class="account-detail">
|
<PageHeader title="新增采购退货" @back="goBack" />
|
<up-form ref="formRef" :model="form" :rules="rules" label-width="120">
|
<u-cell-group title="基本信息" class="form-section">
|
<up-form-item label="退料单号" prop="no">
|
<up-input
|
v-model="form.no"
|
:disabled="form.isDefaultNo"
|
:placeholder="form.isDefaultNo ? '使用系统编号' : '请输入退料单号'"
|
clearable
|
/>
|
<template #right>
|
<up-switch v-model="form.isDefaultNo" @change="onDefaultNoChange" />
|
</template>
|
</up-form-item>
|
<up-form-item label="退货方式" prop="returnType" required>
|
<up-input
|
v-model="returnTypeText"
|
placeholder="请选择"
|
readonly
|
@click="showReturnTypeSheet = true"
|
/>
|
<template #right>
|
<up-icon name="arrow-right" @click="showReturnTypeSheet = true"></up-icon>
|
</template>
|
</up-form-item>
|
<up-form-item label="供应商" prop="supplierId" required>
|
<up-input
|
v-model="supplierText"
|
placeholder="请选择"
|
readonly
|
@click="showSupplierSheet = true"
|
/>
|
<template #right>
|
<up-icon name="arrow-right" @click="showSupplierSheet = true"></up-icon>
|
</template>
|
</up-form-item>
|
<up-form-item label="项目阶段" prop="projectPhase">
|
<up-input
|
v-model="projectPhaseText"
|
placeholder="请选择"
|
readonly
|
@click="showProjectPhaseSheet = true"
|
/>
|
<template #right>
|
<up-icon name="arrow-right" @click="showProjectPhaseSheet = true"></up-icon>
|
</template>
|
</up-form-item>
|
<up-form-item label="制作日期" prop="preparedAt" required>
|
<up-input
|
v-model="form.preparedAt"
|
placeholder="请选择"
|
readonly
|
@click="showPreparedAtPicker = true"
|
/>
|
<template #right>
|
<up-icon name="arrow-right" @click="showPreparedAtPicker = true"></up-icon>
|
</template>
|
</up-form-item>
|
<up-form-item label="制单人" prop="preparedUserId" required>
|
<up-input
|
v-model="preparedUserText"
|
placeholder="请选择"
|
readonly
|
@click="showPreparedUserSheet = true"
|
/>
|
<template #right>
|
<up-icon name="arrow-right" @click="showPreparedUserSheet = true"></up-icon>
|
</template>
|
</up-form-item>
|
<up-form-item label="退料人" prop="returnUserId" required>
|
<up-input
|
v-model="returnUserText"
|
placeholder="请选择"
|
readonly
|
@click="showReturnUserSheet = true"
|
/>
|
<template #right>
|
<up-icon name="arrow-right" @click="showReturnUserSheet = true"></up-icon>
|
</template>
|
</up-form-item>
|
<up-form-item label="采购合同号" prop="purchaseLedgerId" required>
|
<up-input
|
v-model="purchaseContractText"
|
placeholder="请选择"
|
readonly
|
@click="showPurchaseLedgerSheet = true"
|
/>
|
<template #right>
|
<up-icon name="arrow-right" @click="showPurchaseLedgerSheet = true"></up-icon>
|
</template>
|
</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="product-actions">
|
<up-button
|
type="primary"
|
size="small"
|
text="选择产品"
|
:disabled="!form.purchaseLedgerId"
|
@click="goSelectProducts"
|
/>
|
<view class="amount-summary">
|
<text class="amount-text">合计:{{ formatAmount(baseAmount) }}</text>
|
</view>
|
</view>
|
<view v-if="form.purchaseReturnOrderProductsDtos.length === 0" class="empty-products">
|
<text>暂无产品,请先选择产品</text>
|
</view>
|
<view v-else class="product-list">
|
<view
|
v-for="(item, index) in form.purchaseReturnOrderProductsDtos"
|
:key="item.salesLedgerProductId || item.id || index"
|
class="product-card"
|
>
|
<view class="product-header">
|
<view class="product-title">
|
<view class="document-icon">
|
<up-icon name="file-text" size="16" color="#ffffff"></up-icon>
|
</view>
|
<text class="product-name">产品 {{ index + 1 }}</text>
|
</view>
|
<up-icon name="trash" size="18" color="#ee0a24" @click="removeProduct(index)" />
|
</view>
|
<up-divider></up-divider>
|
<view class="product-body">
|
<view class="detail-row">
|
<text class="detail-label">产品大类</text>
|
<text class="detail-value">{{ item.productCategory || "-" }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">规格型号</text>
|
<text class="detail-value">{{ item.specificationModel || "-" }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">数量</text>
|
<text class="detail-value">{{ item.quantity ?? "-" }}</text>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">含税单价(元)</text>
|
<text class="detail-value">{{ formatAmount(item.taxInclusiveUnitPrice) }}</text>
|
</view>
|
<view class="qty-row">
|
<text class="qty-label">退货数量</text>
|
<up-number-box
|
v-model="item.returnQuantity"
|
:min="0"
|
:max="getReturnQtyMax(item)"
|
:step="1"
|
@change="syncRowTotal(item)"
|
/>
|
</view>
|
<view class="detail-row">
|
<text class="detail-label">退货总价(元)</text>
|
<text class="detail-value highlight">{{ formatAmount(item.taxInclusiveTotalPrice) }}</text>
|
</view>
|
</view>
|
</view>
|
</view>
|
</u-cell-group>
|
|
<u-cell-group title="费用信息" class="form-section">
|
<up-form-item label="整单折扣额" prop="totalDiscountAmount">
|
<up-input
|
v-model="form.totalDiscountAmount"
|
type="number"
|
placeholder="请输入"
|
@blur="onDiscountAmountBlur"
|
clearable
|
/>
|
</up-form-item>
|
<up-form-item label="整单折扣率(%)" prop="totalDiscountRate">
|
<up-input
|
v-model="form.totalDiscountRate"
|
type="number"
|
placeholder="请输入"
|
@blur="onDiscountRateBlur"
|
clearable
|
/>
|
</up-form-item>
|
<up-form-item label="成交金额" prop="totalAmount" required>
|
<up-input v-model="form.totalAmount" disabled placeholder="自动计算" />
|
</up-form-item>
|
<up-form-item label="收款方式" prop="incomeType" required>
|
<up-input
|
v-model="incomeTypeText"
|
placeholder="请选择"
|
readonly
|
@click="showIncomeTypeSheet = true"
|
/>
|
<template #right>
|
<up-icon name="arrow-right" @click="showIncomeTypeSheet = true"></up-icon>
|
</template>
|
</up-form-item>
|
</u-cell-group>
|
</up-form>
|
|
<FooterButtons :loading="loading" confirmText="提交" @cancel="goBack" @confirm="handleSubmit" />
|
|
<up-action-sheet
|
:show="showReturnTypeSheet"
|
title="选择退货方式"
|
:actions="returnTypeActions"
|
@select="onSelectReturnType"
|
@close="showReturnTypeSheet = false"
|
/>
|
<up-action-sheet
|
:show="showProjectPhaseSheet"
|
title="选择项目阶段"
|
:actions="projectPhaseActions"
|
@select="onSelectProjectPhase"
|
@close="showProjectPhaseSheet = false"
|
/>
|
<up-action-sheet
|
:show="showSupplierSheet"
|
title="选择供应商"
|
:actions="supplierActions"
|
@select="onSelectSupplier"
|
@close="showSupplierSheet = false"
|
/>
|
<up-action-sheet
|
:show="showPreparedUserSheet"
|
title="选择制单人"
|
:actions="userActions"
|
@select="onSelectPreparedUser"
|
@close="showPreparedUserSheet = false"
|
/>
|
<up-action-sheet
|
:show="showReturnUserSheet"
|
title="选择退料人"
|
:actions="userActions"
|
@select="onSelectReturnUser"
|
@close="showReturnUserSheet = false"
|
/>
|
<up-action-sheet
|
:show="showPurchaseLedgerSheet"
|
title="选择采购合同号"
|
:actions="purchaseLedgerActions"
|
@select="onSelectPurchaseLedger"
|
@close="showPurchaseLedgerSheet = false"
|
/>
|
<up-action-sheet
|
:show="showIncomeTypeSheet"
|
title="选择收款方式"
|
:actions="incomeTypeActions"
|
@select="onSelectIncomeType"
|
@close="showIncomeTypeSheet = false"
|
/>
|
<up-datetime-picker
|
:show="showPreparedAtPicker"
|
v-model="preparedAtPickerValue"
|
mode="date"
|
@confirm="onPreparedAtConfirm"
|
@cancel="showPreparedAtPicker = false"
|
/>
|
</view>
|
</template>
|
|
<script setup>
|
import { computed, onMounted, ref, watch } from "vue";
|
import { onShow } from "@dcloudio/uni-app";
|
import FooterButtons from "@/components/FooterButtons.vue";
|
import { formatDateToYMD } from "@/utils/ruoyi";
|
import { createPurchaseReturnOrder } from "@/api/procurementManagement/purchaseReturnOrder";
|
import { getOptions, purchaseListPage, productList } from "@/api/procurementManagement/procurementLedger";
|
import { userListNoPageByTenantId } from "@/api/system/user";
|
|
const formRef = ref();
|
const loading = ref(false);
|
|
const form = ref({
|
no: "",
|
isDefaultNo: true,
|
returnType: 0,
|
supplierId: undefined,
|
supplierName: "",
|
projectPhase: undefined,
|
preparedAt: "",
|
preparedUserId: undefined,
|
preparedUserName: "",
|
returnUserId: undefined,
|
returnUserName: "",
|
purchaseLedgerId: undefined,
|
purchaseContractNumber: "",
|
remark: "",
|
totalDiscountAmount: 0,
|
totalDiscountRate: "",
|
totalAmount: 0,
|
incomeType: undefined,
|
purchaseReturnOrderProductsDtos: [],
|
});
|
|
const rules = {
|
returnType: [{ required: true, message: "请选择退货方式", trigger: "change" }],
|
supplierId: [{ required: true, message: "请选择供应商", trigger: "change" }],
|
preparedAt: [{ required: true, message: "请选择制作日期", trigger: "change" }],
|
preparedUserId: [{ required: true, message: "请选择制单人", trigger: "change" }],
|
returnUserId: [{ required: true, message: "请选择退料人", trigger: "change" }],
|
purchaseLedgerId: [{ required: true, message: "请选择采购合同号", trigger: "change" }],
|
totalAmount: [{ required: true, message: "成交金额不能为空", trigger: "change" }],
|
incomeType: [{ required: true, message: "请选择收款方式", trigger: "change" }],
|
};
|
|
const showReturnTypeSheet = ref(false);
|
const showProjectPhaseSheet = ref(false);
|
const showSupplierSheet = ref(false);
|
const showPreparedUserSheet = ref(false);
|
const showReturnUserSheet = ref(false);
|
const showPurchaseLedgerSheet = ref(false);
|
const showIncomeTypeSheet = ref(false);
|
const showPreparedAtPicker = ref(false);
|
const preparedAtPickerValue = ref(Date.now());
|
|
const supplierOptions = ref([]);
|
const userOptions = ref([]);
|
const purchaseLedgerOptions = ref([]);
|
|
const returnTypeActions = [
|
{ name: "退货退款", value: 0 },
|
{ name: "拒收", value: 1 },
|
];
|
const projectPhaseActions = [
|
{ name: "立项", value: 0 },
|
{ name: "设计", value: 1 },
|
{ name: "采购", value: 2 },
|
{ name: "生产", value: 3 },
|
{ name: "出货", value: 4 },
|
];
|
const incomeTypeActions = [
|
{ name: "现金", value: "0" },
|
{ name: "支票", value: "1" },
|
{ name: "银行转账", value: "2" },
|
{ name: "其他", value: "3" },
|
];
|
|
const returnTypeText = computed(() => {
|
return returnTypeActions.find(i => String(i.value) === String(form.value.returnType))?.name || "";
|
});
|
const projectPhaseText = computed(() => {
|
return projectPhaseActions.find(i => String(i.value) === String(form.value.projectPhase))?.name || "";
|
});
|
const supplierText = computed(() => {
|
return supplierOptions.value.find(i => String(i.id) === String(form.value.supplierId))?.supplierName || "";
|
});
|
const preparedUserText = computed(() => {
|
return userOptions.value.find(i => String(i.userId) === String(form.value.preparedUserId))?.nickName || "";
|
});
|
const returnUserText = computed(() => {
|
return userOptions.value.find(i => String(i.userId) === String(form.value.returnUserId))?.nickName || "";
|
});
|
const purchaseContractText = computed(() => {
|
return purchaseLedgerOptions.value.find(i => String(i.id) === String(form.value.purchaseLedgerId))?.purchaseContractNumber || "";
|
});
|
const incomeTypeText = computed(() => {
|
return incomeTypeActions.find(i => String(i.value) === String(form.value.incomeType))?.name || "";
|
});
|
|
const supplierActions = computed(() => {
|
return supplierOptions.value.map(i => ({ name: i.supplierName, value: i.id }));
|
});
|
const userActions = computed(() => {
|
return userOptions.value.map(i => ({ name: i.nickName, value: i.userId }));
|
});
|
const purchaseLedgerActions = computed(() => {
|
return purchaseLedgerOptions.value.map(i => ({ name: i.purchaseContractNumber, value: i.id }));
|
});
|
|
const toNumber = val => {
|
const num = Number(val);
|
return Number.isNaN(num) ? 0 : num;
|
};
|
|
const formatAmount = value => {
|
if (value === null || value === undefined || value === "") return "0.00";
|
const num = Number(value);
|
if (Number.isNaN(num)) return "0.00";
|
return num.toFixed(2);
|
};
|
|
const baseAmount = computed(() => {
|
const rows = form.value.purchaseReturnOrderProductsDtos || [];
|
return rows.reduce((sum, item) => sum + toNumber(item.taxInclusiveTotalPrice), 0);
|
});
|
|
const syncTotalAmount = () => {
|
const total = baseAmount.value - toNumber(form.value.totalDiscountAmount);
|
form.value.totalAmount = Number(total.toFixed(2));
|
};
|
|
const getReturnQtyMax = row => {
|
const qty = Number(row?.quantity);
|
if (Number.isNaN(qty) || qty < 0) return 0;
|
return qty;
|
};
|
|
const syncRowTotal = row => {
|
if (!row) return;
|
const qty = toNumber(row.returnQuantity);
|
const unitPrice = toNumber(row.taxInclusiveUnitPrice);
|
row.taxInclusiveTotalPrice = Number((qty * unitPrice).toFixed(2));
|
syncTotalAmount();
|
};
|
|
const removeProduct = index => {
|
form.value.purchaseReturnOrderProductsDtos.splice(index, 1);
|
syncTotalAmount();
|
};
|
|
const resetFeeInfo = () => {
|
form.value.totalDiscountAmount = 0;
|
form.value.totalDiscountRate = "";
|
form.value.totalAmount = 0;
|
form.value.incomeType = undefined;
|
};
|
|
const onDefaultNoChange = checked => {
|
if (checked) form.value.no = "";
|
};
|
|
const onSelectReturnType = action => {
|
form.value.returnType = action.value;
|
showReturnTypeSheet.value = false;
|
};
|
const onSelectProjectPhase = action => {
|
form.value.projectPhase = action.value;
|
showProjectPhaseSheet.value = false;
|
};
|
const onSelectSupplier = action => {
|
form.value.supplierId = action.value;
|
form.value.supplierName = supplierOptions.value.find(i => String(i.id) === String(action.value))?.supplierName || "";
|
form.value.purchaseLedgerId = undefined;
|
form.value.purchaseContractNumber = "";
|
form.value.purchaseReturnOrderProductsDtos = [];
|
resetFeeInfo();
|
showSupplierSheet.value = false;
|
fetchPurchaseLedgerOptions();
|
};
|
const onSelectPreparedUser = action => {
|
form.value.preparedUserId = action.value;
|
form.value.preparedUserName = userOptions.value.find(i => String(i.userId) === String(action.value))?.nickName || "";
|
showPreparedUserSheet.value = false;
|
};
|
const onSelectReturnUser = action => {
|
form.value.returnUserId = action.value;
|
form.value.returnUserName = userOptions.value.find(i => String(i.userId) === String(action.value))?.nickName || "";
|
showReturnUserSheet.value = false;
|
};
|
const onSelectPurchaseLedger = action => {
|
form.value.purchaseLedgerId = action.value;
|
form.value.purchaseContractNumber =
|
purchaseLedgerOptions.value.find(i => String(i.id) === String(action.value))?.purchaseContractNumber || "";
|
form.value.purchaseReturnOrderProductsDtos = [];
|
resetFeeInfo();
|
showPurchaseLedgerSheet.value = false;
|
};
|
const onSelectIncomeType = action => {
|
form.value.incomeType = action.value;
|
showIncomeTypeSheet.value = false;
|
};
|
|
const onPreparedAtConfirm = e => {
|
form.value.preparedAt = formatDateToYMD(e.value);
|
showPreparedAtPicker.value = false;
|
};
|
|
const onDiscountRateBlur = () => {
|
const rate = toNumber(form.value.totalDiscountRate);
|
if (rate < 0 || rate > 100) {
|
uni.showToast({ title: "折扣率需在0-100", icon: "none" });
|
return;
|
}
|
form.value.totalDiscountAmount = Number((baseAmount.value * (rate / 100)).toFixed(2));
|
syncTotalAmount();
|
};
|
|
const onDiscountAmountBlur = () => {
|
const amount = toNumber(form.value.totalDiscountAmount);
|
if (amount < 0) {
|
form.value.totalDiscountAmount = 0;
|
}
|
const base = baseAmount.value;
|
if (base <= 0) {
|
form.value.totalDiscountRate = "";
|
syncTotalAmount();
|
return;
|
}
|
if (toNumber(form.value.totalDiscountAmount) > base) {
|
form.value.totalDiscountAmount = Number(base.toFixed(2));
|
}
|
const rate = (toNumber(form.value.totalDiscountAmount) / base) * 100;
|
form.value.totalDiscountRate = Number(rate.toFixed(2));
|
syncTotalAmount();
|
};
|
|
const goBack = () => {
|
uni.removeStorageSync("purchaseReturnOrderSelectedProducts");
|
uni.navigateBack();
|
};
|
|
const goSelectProducts = () => {
|
if (!form.value.purchaseLedgerId) return;
|
uni.navigateTo({
|
url: `/pages/procurementManagement/purchaseReturnOrder/productList?purchaseLedgerId=${form.value.purchaseLedgerId}`,
|
});
|
};
|
|
const fetchSupplierOptions = () => {
|
getOptions()
|
.then(res => {
|
supplierOptions.value = res.data || [];
|
})
|
.catch(() => {
|
supplierOptions.value = [];
|
});
|
};
|
|
const fetchUserOptions = () => {
|
userListNoPageByTenantId()
|
.then(res => {
|
userOptions.value = res.data || [];
|
})
|
.catch(() => {
|
userOptions.value = [];
|
});
|
};
|
|
const fetchPurchaseLedgerOptions = () => {
|
purchaseLedgerOptions.value = [];
|
if (!form.value.supplierId) return;
|
purchaseListPage({
|
current: -1,
|
size: -1,
|
supplierId: form.value.supplierId,
|
approvalStatus: 3,
|
})
|
.then(res => {
|
purchaseLedgerOptions.value = res?.data?.records || [];
|
})
|
.catch(() => {
|
purchaseLedgerOptions.value = [];
|
});
|
};
|
|
const mergeSelectedProducts = selectedRows => {
|
const existing = new Set((form.value.purchaseReturnOrderProductsDtos || []).map(i => String(i.salesLedgerProductId || i.id)));
|
const toAdd = (selectedRows || [])
|
.filter(i => !existing.has(String(i.id)))
|
.map(i => ({
|
...i,
|
salesLedgerProductId: i.id,
|
returnQuantity: 0,
|
taxInclusiveTotalPrice: 0,
|
}));
|
form.value.purchaseReturnOrderProductsDtos.push(...toAdd);
|
syncTotalAmount();
|
};
|
|
const loadProductsFromPurchaseLedger = () => {
|
if (!form.value.purchaseLedgerId) return;
|
uni.showLoading({ title: "加载产品...", mask: true });
|
productList({ salesLedgerId: form.value.purchaseLedgerId, type: 2 })
|
.then(res => {
|
const rows = res.data || [];
|
mergeSelectedProducts(rows);
|
})
|
.catch(() => {
|
uni.showToast({ title: "加载产品失败", icon: "error" });
|
})
|
.finally(() => {
|
uni.hideLoading();
|
});
|
};
|
|
const validateProducts = () => {
|
const rows = form.value.purchaseReturnOrderProductsDtos || [];
|
if (rows.length === 0) {
|
uni.showToast({ title: "请先选择产品", icon: "none" });
|
return false;
|
}
|
const invalid = rows.findIndex(i => {
|
const qty = toNumber(i.returnQuantity);
|
if (qty <= 0) return true;
|
if (qty > getReturnQtyMax(i)) return true;
|
return false;
|
});
|
if (invalid !== -1) {
|
uni.showToast({ title: `第${invalid + 1}行退货数量不合法`, icon: "none" });
|
return false;
|
}
|
return true;
|
};
|
|
const handleSubmit = async () => {
|
if (!validateProducts()) return;
|
const valid = await formRef.value.validate().catch(() => false);
|
if (!valid) return;
|
loading.value = true;
|
const rows = (form.value.purchaseReturnOrderProductsDtos || []).map(i => {
|
const cloned = { ...i };
|
syncRowTotal(cloned);
|
return cloned;
|
});
|
const payload = {
|
...form.value,
|
purchaseReturnOrderProductsDtos: rows.filter(i => toNumber(i.returnQuantity) > 0),
|
};
|
createPurchaseReturnOrder(payload)
|
.then(() => {
|
uni.showToast({ title: "提交成功", icon: "success" });
|
uni.removeStorageSync("purchaseReturnOrderSelectedProducts");
|
uni.navigateBack();
|
})
|
.catch(() => {
|
uni.showToast({ title: "提交失败", icon: "error" });
|
})
|
.finally(() => {
|
loading.value = false;
|
});
|
};
|
|
watch(
|
() => baseAmount.value,
|
() => {
|
syncTotalAmount();
|
}
|
);
|
|
onMounted(() => {
|
form.value.preparedAt = formatDateToYMD(Date.now());
|
preparedAtPickerValue.value = Date.now();
|
fetchSupplierOptions();
|
fetchUserOptions();
|
});
|
|
onShow(() => {
|
const stored = uni.getStorageSync("purchaseReturnOrderSelectedProducts");
|
if (stored) {
|
try {
|
const rows = JSON.parse(stored);
|
mergeSelectedProducts(rows);
|
uni.removeStorageSync("purchaseReturnOrderSelectedProducts");
|
} catch {
|
uni.removeStorageSync("purchaseReturnOrderSelectedProducts");
|
}
|
}
|
});
|
|
const showAutoLoadModalOnceKey = "purchaseReturnOrderAutoLoadShown";
|
watch(
|
() => form.value.purchaseLedgerId,
|
(val, oldVal) => {
|
if (!val || String(val) === String(oldVal)) return;
|
if (uni.getStorageSync(showAutoLoadModalOnceKey)) return;
|
uni.setStorageSync(showAutoLoadModalOnceKey, "1");
|
uni.showModal({
|
title: "提示",
|
content: "是否自动加载该采购合同下全部产品?",
|
success: res => {
|
if (res.confirm) loadProductsFromPurchaseLedger();
|
},
|
});
|
}
|
);
|
</script>
|
|
<style scoped lang="scss">
|
@import "@/styles/procurement-common.scss";
|
|
.account-detail {
|
min-height: 100vh;
|
background: #f8f9fa;
|
padding-bottom: 90px;
|
}
|
|
.form-section {
|
margin: 12px;
|
border-radius: 12px;
|
overflow: hidden;
|
}
|
|
.product-actions {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
padding: 12px 12px 0 12px;
|
}
|
|
.amount-summary {
|
display: flex;
|
align-items: center;
|
}
|
|
.amount-text {
|
font-size: 14px;
|
color: #333;
|
font-weight: 600;
|
}
|
|
.empty-products {
|
padding: 16px 12px;
|
color: #999;
|
font-size: 14px;
|
}
|
|
.product-list {
|
padding: 12px;
|
display: flex;
|
flex-direction: column;
|
gap: 12px;
|
}
|
|
.product-card {
|
background: #fff;
|
border-radius: 12px;
|
padding: 0 12px;
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
}
|
|
.product-header {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
padding: 12px 0;
|
}
|
|
.product-title {
|
display: flex;
|
align-items: center;
|
gap: 8px;
|
}
|
|
.product-name {
|
font-size: 14px;
|
color: #333;
|
font-weight: 500;
|
}
|
|
.product-body {
|
padding: 12px 0;
|
}
|
|
.qty-row {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
padding: 8px 0;
|
}
|
|
.qty-label {
|
font-size: 12px;
|
color: #777;
|
}
|
</style>
|