| | |
| | | size="small" |
| | | type="primary" |
| | | @click="goStructure(item)">查看详情</up-button> |
| | | <up-button class="action-btn" |
| | | size="small" |
| | | type="warning" |
| | | @click="openEdit(item)">修改</up-button> |
| | | <up-button class="action-btn" |
| | | size="small" |
| | | type="error" |
| | | @click="handleDelete(item)">删除</up-button> |
| | | </view> |
| | | </view> |
| | | <up-loadmore :status="pageStatus" /> |
| | |
| | | <up-empty text="暂无BOM数据" |
| | | mode="list"></up-empty> |
| | | </view> |
| | | <view class="fab-button" |
| | | @click="openAdd"> |
| | | <up-icon name="plus" |
| | | size="24" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | <up-popup :show="showFormPopup" |
| | | mode="bottom" |
| | | round |
| | | @close="closeFormPopup"> |
| | | <view class="popup-container"> |
| | | <view class="popup-header"> |
| | | <text class="popup-cancel" |
| | | @click="closeFormPopup">取消</text> |
| | | <text class="popup-title">{{ formMode === 'add' ? '新增BOM' : '修改BOM' }}</text> |
| | | <text class="popup-confirm" |
| | | @click="submitForm">确定</text> |
| | | </view> |
| | | <view class="popup-body"> |
| | | <up-form ref="bomFormRef" |
| | | :model="bomForm" |
| | | :rules="bomRules" |
| | | label-width="110"> |
| | | <up-form-item label="产品" |
| | | prop="productModelId" |
| | | required> |
| | | <up-input v-model="bomForm.productName" |
| | | readonly |
| | | placeholder="点击选择产品" |
| | | @click="openProductPicker" /> |
| | | <template #right> |
| | | <up-icon name="arrow-right" |
| | | @click="openProductPicker"></up-icon> |
| | | </template> |
| | | </up-form-item> |
| | | <up-form-item label="规格型号"> |
| | | <up-input v-model="bomForm.productModelName" |
| | | readonly |
| | | placeholder="--" /> |
| | | </up-form-item> |
| | | <up-form-item label="版本号" |
| | | prop="version" |
| | | required> |
| | | <up-input v-model="bomForm.version" |
| | | placeholder="请输入版本号" |
| | | clearable /> |
| | | </up-form-item> |
| | | <up-form-item label="备注" |
| | | prop="remark"> |
| | | <up-textarea v-model="bomForm.remark" |
| | | placeholder="请输入备注" |
| | | auto-height /> |
| | | </up-form-item> |
| | | </up-form> |
| | | </view> |
| | | </view> |
| | | </up-popup> |
| | | <up-popup :show="showProductPicker" |
| | | mode="bottom" |
| | | round |
| | | @close="showProductPicker = false"> |
| | | <view class="popup-container"> |
| | | <view class="popup-header"> |
| | | <text class="popup-cancel" |
| | | @click="showProductPicker = false">取消</text> |
| | | <text class="popup-title">选择产品</text> |
| | | <text class="popup-confirm" |
| | | @click="handleProductSearch">搜索</text> |
| | | </view> |
| | | <view class="popup-body"> |
| | | <view class="picker-search"> |
| | | <up-input v-model="productQuery.productName" |
| | | placeholder="产品名称" |
| | | clearable |
| | | @change="handleProductSearch" /> |
| | | <up-input v-model="productQuery.model" |
| | | placeholder="规格型号" |
| | | clearable |
| | | @change="handleProductSearch" /> |
| | | </view> |
| | | <scroll-view scroll-y |
| | | class="picker-list" |
| | | @scrolltolower="loadMoreProducts"> |
| | | <view v-for="row in productList" |
| | | :key="row.id" |
| | | class="picker-item" |
| | | @click="selectProduct(row)"> |
| | | <view class="picker-item__title"> |
| | | <text>{{ row.productName || '-' }}</text> |
| | | </view> |
| | | <view class="picker-item__sub"> |
| | | <text>{{ row.model || '-' }}</text> |
| | | <text class="picker-item__unit">{{ row.unit || '-' }}</text> |
| | | </view> |
| | | </view> |
| | | <up-loadmore :status="productPageStatus" /> |
| | | </scroll-view> |
| | | </view> |
| | | </view> |
| | | </up-popup> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { reactive, ref } from "vue"; |
| | | import { onReachBottom, onShow } from "@dcloudio/uni-app"; |
| | | import { listPage } from "@/api/productionManagement/bom"; |
| | | import { |
| | | listPage, |
| | | add, |
| | | update, |
| | | batchDelete, |
| | | getProductList, |
| | | } from "@/api/productionManagement/bom"; |
| | | |
| | | const queryParams = reactive({ |
| | | productName: "", |
| | |
| | | size: 3, |
| | | total: 0, |
| | | }); |
| | | const showFormPopup = ref(false); |
| | | const formMode = ref("add"); |
| | | const bomFormRef = ref(null); |
| | | const bomForm = reactive({ |
| | | id: undefined, |
| | | productName: "", |
| | | productModelName: "", |
| | | productModelId: "", |
| | | remark: "", |
| | | version: "", |
| | | }); |
| | | const bomRules = { |
| | | productModelId: [{ required: true, message: "请选择产品", trigger: "blur" }], |
| | | version: [{ required: true, message: "请输入版本号", trigger: "blur" }], |
| | | }; |
| | | |
| | | const showProductPicker = ref(false); |
| | | const productQuery = reactive({ |
| | | productName: "", |
| | | model: "", |
| | | }); |
| | | const productList = ref([]); |
| | | const productPage = reactive({ |
| | | current: 1, |
| | | size: 20, |
| | | total: 0, |
| | | }); |
| | | const productPageStatus = ref("loadmore"); |
| | | |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | |
| | | }); |
| | | }; |
| | | |
| | | const openAdd = () => { |
| | | formMode.value = "add"; |
| | | Object.assign(bomForm, { |
| | | id: undefined, |
| | | productName: "", |
| | | productModelName: "", |
| | | productModelId: "", |
| | | remark: "", |
| | | version: "", |
| | | }); |
| | | showFormPopup.value = true; |
| | | }; |
| | | |
| | | const openEdit = row => { |
| | | formMode.value = "edit"; |
| | | Object.assign(bomForm, { |
| | | id: row.id, |
| | | productName: row.productName || "", |
| | | productModelName: row.productModelName || "", |
| | | productModelId: row.productModelId || "", |
| | | remark: row.remark || "", |
| | | version: row.version || "", |
| | | }); |
| | | showFormPopup.value = true; |
| | | }; |
| | | |
| | | const closeFormPopup = () => { |
| | | showFormPopup.value = false; |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | if (!bomFormRef.value) return; |
| | | bomFormRef.value.validate(valid => { |
| | | if (!valid) return; |
| | | const payload = { ...bomForm }; |
| | | const req = formMode.value === "add" ? add(payload) : update(payload); |
| | | req |
| | | .then(res => { |
| | | if (res && res.code !== undefined && res.code !== 200) { |
| | | uni.showToast({ |
| | | title: res.msg || "提交失败", |
| | | icon: "none", |
| | | }); |
| | | return; |
| | | } |
| | | uni.showToast({ |
| | | title: "提交成功", |
| | | icon: "success", |
| | | }); |
| | | closeFormPopup(); |
| | | handleSearch(); |
| | | }) |
| | | .catch(() => { |
| | | uni.showToast({ |
| | | title: "提交失败", |
| | | icon: "error", |
| | | }); |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | const handleDelete = row => { |
| | | if (!row?.id) return; |
| | | uni.showModal({ |
| | | title: "提示", |
| | | content: "确认删除该BOM?", |
| | | confirmText: "确认", |
| | | cancelText: "取消", |
| | | success: res => { |
| | | if (!res.confirm) return; |
| | | batchDelete([row.id]) |
| | | .then(result => { |
| | | if (result && result.code !== undefined && result.code !== 200) { |
| | | uni.showToast({ |
| | | title: result.msg || "删除失败", |
| | | icon: "none", |
| | | }); |
| | | return; |
| | | } |
| | | uni.showToast({ |
| | | title: "删除成功", |
| | | icon: "success", |
| | | }); |
| | | handleSearch(); |
| | | }) |
| | | .catch(() => { |
| | | uni.showToast({ |
| | | title: "删除失败", |
| | | icon: "error", |
| | | }); |
| | | }); |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | const openProductPicker = () => { |
| | | showProductPicker.value = true; |
| | | handleProductSearch(); |
| | | }; |
| | | |
| | | const handleProductSearch = () => { |
| | | productPage.current = 1; |
| | | productPageStatus.value = "loadmore"; |
| | | productList.value = []; |
| | | loadMoreProducts(); |
| | | }; |
| | | |
| | | const loadMoreProducts = () => { |
| | | if ( |
| | | productPageStatus.value === "loading" || |
| | | productPageStatus.value === "nomore" |
| | | ) { |
| | | return; |
| | | } |
| | | productPageStatus.value = "loading"; |
| | | getProductList({ |
| | | current: productPage.current, |
| | | size: productPage.size, |
| | | productName: productQuery.productName, |
| | | model: productQuery.model, |
| | | }) |
| | | .then(res => { |
| | | const records = res?.data?.records || res?.records || res?.data || []; |
| | | const total = res?.data?.total || res?.total || 0; |
| | | const next = Array.isArray(records) ? records : []; |
| | | productList.value = |
| | | productPage.current === 1 ? next : [...productList.value, ...next]; |
| | | productPage.total = Number(total || productList.value.length); |
| | | if (productList.value.length >= productPage.total) { |
| | | productPageStatus.value = "nomore"; |
| | | } else { |
| | | productPageStatus.value = "loadmore"; |
| | | productPage.current++; |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | productPageStatus.value = "loadmore"; |
| | | }); |
| | | }; |
| | | |
| | | const selectProduct = row => { |
| | | bomForm.productModelId = row.id; |
| | | bomForm.productName = row.productName || ""; |
| | | bomForm.productModelName = row.model || ""; |
| | | showProductPicker.value = false; |
| | | }; |
| | | |
| | | onReachBottom(() => { |
| | | getList(); |
| | | }); |
| | |
| | | margin: 0 !important; |
| | | margin-bottom: 15rpx !important; |
| | | } |
| | | |
| | | .popup-container { |
| | | background: #fff; |
| | | border-radius: 20rpx 20rpx 0 0; |
| | | max-height: 80vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .popup-header { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 24rpx 28rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | } |
| | | |
| | | .popup-title { |
| | | font-size: 30rpx; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .popup-cancel { |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | } |
| | | |
| | | .popup-confirm { |
| | | font-size: 28rpx; |
| | | color: #006cfb; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .popup-body { |
| | | padding: 20rpx 24rpx 30rpx; |
| | | overflow: hidden; |
| | | flex: 1; |
| | | } |
| | | |
| | | .picker-search { |
| | | display: flex; |
| | | gap: 16rpx; |
| | | margin-bottom: 16rpx; |
| | | } |
| | | |
| | | .picker-list { |
| | | height: 60vh; |
| | | } |
| | | |
| | | .picker-item { |
| | | padding: 22rpx 0; |
| | | border-bottom: 1rpx solid #f5f5f5; |
| | | } |
| | | |
| | | .picker-item__title { |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .picker-item__sub { |
| | | margin-top: 6rpx; |
| | | font-size: 24rpx; |
| | | color: #666; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | gap: 16rpx; |
| | | } |
| | | |
| | | .picker-item__unit { |
| | | color: #999; |
| | | white-space: nowrap; |
| | | } |
| | | </style> |