From bd712637441c43d6e23a8577b748a5d2b3365745 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期五, 21 十一月 2025 15:03:59 +0800
Subject: [PATCH] 添加自定义出库页面
---
src/api/inventoryManagement/stockManage.js | 76 ++++++
src/pages/index.vue | 11
src/pages.json | 7
src/pages/inventoryManagement/issueManagement/index.vue | 564 +++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 657 insertions(+), 1 deletions(-)
diff --git a/src/api/inventoryManagement/stockManage.js b/src/api/inventoryManagement/stockManage.js
new file mode 100644
index 0000000..4f5d957
--- /dev/null
+++ b/src/api/inventoryManagement/stockManage.js
@@ -0,0 +1,76 @@
+import request from "@/utils/request";
+
+// 鏌ヨ搴撳瓨淇℃伅鍒楄〃
+export const getStockManagePage = (params) => {
+ return request({
+ url: "/stockin/listPageCopy",
+ method: "get",
+ params,
+ });
+};
+
+// 鏌ヨ鐢熶骇鍏ュ簱搴撳瓨淇℃伅鍒楄〃
+export const getStockManagePageByProduction = (params) => {
+ return request({
+ url: "/stockin/listPageCopyByProduction",
+ method: "get",
+ params,
+ });
+};
+
+// 鏌ヨ鑷畾涔夊叆搴撳簱瀛樹俊鎭垪琛�
+export const getStockManagePageByCustom = (params) => {
+ return request({
+ url: "/stockin/listPageCopyByCustom",
+ method: "get",
+ params,
+ });
+};
+
+
+// 淇敼搴撳瓨淇℃伅
+export const updateStockManage = (data) => {
+ return request({
+ url: "/stockmanagement/update",
+ method: "put",
+ data,
+ });
+};
+
+// 鍒犻櫎搴撳瓨淇℃伅
+export function delStockManage(ids) {
+ return request({
+ url: '/stockin/del',
+ method: 'post',
+ data: ids
+ })
+}
+
+// 瀵煎嚭搴撳瓨淇℃伅
+export function exportStockManage(query) {
+ return request({
+ url: '/stockmanagement/export',
+ method: 'get',
+ params: query,
+ responseType: 'blob'
+ })
+}
+
+// 鍑哄簱绠$悊-棰嗙敤鎺ュ彛
+export const stockOut = (data) => {
+ return request({
+ url: '/stockmanagement/stockout',
+ method: 'post',
+ data: data
+ })
+}
+
+//鏍规嵁id鑾峰彇搴撳瓨淇℃伅
+export function getStockManageById(id) {
+ return request({
+ url: '/stockmanagement/' + id,
+ method: 'get'
+ })
+}
+
+//
\ No newline at end of file
diff --git a/src/pages.json b/src/pages.json
index 654c337..68210cf 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -469,6 +469,13 @@
"navigationBarTitleText": "鏂板鍏ュ簱",
"navigationStyle": "custom"
}
+ },
+ {
+ "path": "pages/inventoryManagement/issueManagement/index",
+ "style": {
+ "navigationBarTitleText": "鑷畾涔夊嚭搴�",
+ "navigationStyle": "custom"
+ }
}
],
"subPackages": [
diff --git a/src/pages/index.vue b/src/pages/index.vue
index 04da41f..67cb6b4 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -125,7 +125,7 @@
<view class="common-module collaboration-module">
<view class="module-header">
<view class="module-title-container">
- <text class="module-title">鍏ュ簱绠$悊</text>
+ <text class="module-title">浠撳偍鐗╂祦</text>
</view>
</view>
<view class="module-content">
@@ -328,6 +328,10 @@
icon: '/static/images/icon/rukuguanli@2x.png',
label: '鑷畾涔夊叆搴�',
},
+ {
+ icon: '/static/images/icon/rukuguanli@2x.png',
+ label: '鑷畾涔夊嚭搴�',
+ },
]);
// 鐢熶骇绠℃帶鍔熻兘鏁版嵁
@@ -493,6 +497,11 @@
url: '/pages/inventoryManagement/receiptManagement/index'
});
break;
+ case '鑷畾涔夊嚭搴�':
+ uni.navigateTo({
+ url: '/pages/inventoryManagement/issueManagement/index'
+ });
+ break;
case '鐢熶骇璁㈠崟':
uni.navigateTo({
url: '/pages/productionManagement/productionOrder/index'
diff --git a/src/pages/inventoryManagement/issueManagement/index.vue b/src/pages/inventoryManagement/issueManagement/index.vue
new file mode 100644
index 0000000..5a2b4a1
--- /dev/null
+++ b/src/pages/inventoryManagement/issueManagement/index.vue
@@ -0,0 +1,564 @@
+<template>
+ <view class="stock-out-page">
+ <!-- 椤甸潰鏍囬 -->
+ <PageHeader title="鑷畾涔夊嚭搴�" @back="goBack" />
+
+ <!-- 鎼滅储鍖哄煙 -->
+ <view class="search-section">
+ <view class="search-bar">
+ <view class="search-input">
+ <u-input
+ v-model="searchForm.supplierName"
+ placeholder="璇疯緭鍏ヤ緵搴斿晢鍚嶇О"
+ border="none"
+ clearable
+ />
+ </view>
+ <view class="search-button" @click="handleQuery">
+ <u-icon name="search" size="24" color="#999"></u-icon>
+ </view>
+ </view>
+ <view class="date-filter" @click="openDatePickerHandler">
+ <text class="date-text">{{ searchForm.timeStr || '閫夋嫨鏃ユ湡' }}</text>
+ <up-icon name="calendar" size="18" color="#999"></up-icon>
+ </view>
+ </view>
+
+ <!-- 鏃ユ湡閫夋嫨鍣� -->
+ <up-popup :show="showDatePicker" mode="bottom" @close="showDatePicker = false">
+ <up-datetime-picker
+ :show="true"
+ v-model="dateValue"
+ @confirm="onDateConfirm"
+ @cancel="showDatePicker = false"
+ mode="date"
+ />
+ </up-popup>
+
+ <!-- 鏁版嵁鍒楄〃 -->
+ <view class="stock-list" v-if="tableData.length > 0">
+ <view v-for="(item, index) in tableData" :key="item.id" class="stock-item">
+ <view class="item-header">
+ <view class="item-left">
+ <view class="batch-icon">
+ <u-icon name="file-text" size="16" color="#ffffff"></u-icon>
+ </view>
+ <text class="batch-text">{{ item.inboundBatches || '鏈煡鎵规' }}</text>
+ </view>
+ <view class="item-right">
+ <text class="time-text">{{ item.inboundDate || item.createTime || '-' }}</text>
+ </view>
+ </view>
+ <u-divider></u-divider>
+
+ <view class="item-details">
+ <view class="detail-row">
+ <text class="detail-label">渚涘簲鍟嗗悕绉�</text>
+ <text class="detail-value">{{ item.supplierName || '鏈煡渚涘簲鍟�' }}</text>
+ </view>
+ <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 highlight">{{ item.inboundNum || 0 }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍚◣鍗曚环</text>
+ <text class="detail-value">楼{{ item.taxInclusiveUnitPrice || 0 }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍚◣鎬讳环</text>
+ <text class="detail-value price">楼{{ item.taxInclusiveTotalPrice || 0 }}</text>
+ </view>
+ </view>
+
+ <view class="item-actions">
+ <u-button type="primary" size="small" @click="openForm(item)">棰嗙敤</u-button>
+ <u-button type="warning" size="small" plain @click="handleOut">瀵煎嚭</u-button>
+ </view>
+ </view>
+ </view>
+
+ <view v-else class="no-data">
+ <text>鏆傛棤鏁版嵁</text>
+ </view>
+
+ <!-- 鍔犺浇鏇村 -->
+ <view class="load-more" v-if="tableData.length > 0">
+ <u-loadmore :status="loadStatus" @loadmore="loadMore" />
+ </view>
+
+ <!-- 鍑哄簱琛ㄥ崟寮圭獥 -->
+ <u-popup
+ v-model="dialogFormVisible"
+ mode="center"
+ :closeable="true"
+ @close="closeDia"
+ round="10"
+ >
+ <view class="popup-content">
+ <view class="popup-header">
+ <text class="popup-title">鏂板鍑哄簱</text>
+ </view>
+
+ <view class="popup-body">
+ <u-form :model="form" :rules="rules" ref="formRef" labelWidth="80">
+ <u-form-item label="鍑哄簱鏁伴噺" prop="inboundQuantity" borderBottom>
+ <u-input
+ v-model="form.inboundQuantity"
+ placeholder="璇疯緭鍏ュ嚭搴撴暟閲�"
+ type="number"
+ border="none"
+ />
+ </u-form-item>
+
+ <u-form-item label="鍑哄簱鏃ユ湡" prop="inboundTime" borderBottom>
+ <u-input
+ v-model="form.inboundTime"
+ placeholder="璇烽�夋嫨鍑哄簱鏃ユ湡"
+ border="none"
+ readonly
+ @click="showOutDatePicker = true"
+ >
+ <template #suffix>
+ <u-icon name="calendar" size="18"></u-icon>
+ </template>
+ </u-input>
+ </u-form-item>
+
+ <u-form-item label="鍑哄簱浜�" prop="nickName" borderBottom>
+ <u-select
+ v-model="form.nickName"
+ :list="userList"
+ labelName="nickName"
+ valueName="userId"
+ placeholder="璇烽�夋嫨鍑哄簱浜�"
+ ></u-select>
+ </u-form-item>
+ </u-form>
+ </view>
+
+ <view class="popup-footer">
+ <u-button type="primary" @click="submitForm" size="normal">纭</u-button>
+ <u-button @click="closeDia" size="normal" plain>鍙栨秷</u-button>
+ </view>
+ </view>
+ </u-popup>
+
+ <!-- 鍑哄簱鏃ユ湡閫夋嫨鍣� -->
+ <u-datetime-picker
+ v-model="form.inboundTime"
+ :show="showOutDatePicker"
+ mode="date"
+ @confirm="showOutDatePicker = false"
+ @cancel="showOutDatePicker = false"
+ />
+ </view>
+</template>
+
+<script setup>
+import { ref, reactive, toRefs, onMounted, getCurrentInstance, nextTick } from 'vue'
+import dayjs from 'dayjs'
+import PageHeader from '@/components/PageHeader.vue'
+import useUserStore from '@/store/modules/user'
+import { formatDateToYMD } from '@/utils/ruoyi'
+import { userListNoPageByTenantId } from "@/api/system/user.js";
+import { getInPageByCustom } from "@/api/inventoryManagement/stockIn.js";
+import { stockOut } from "@/api/inventoryManagement/stockManage.js";
+
+const userStore = useUserStore()
+const { proxy } = getCurrentInstance()
+
+// 杩斿洖涓婁竴椤�
+const goBack = () => {
+ uni.navigateBack()
+}
+
+// 鎵撳紑鏃ユ湡閫夋嫨鍣紙绠�鍗曞彲闈狅級
+const openDatePickerHandler = () => {
+ // 鑻ュ凡鏈夐�変腑鏃ユ湡锛岀敤瀹冨垵濮嬪寲锛涘惁鍒欑敤浠婂ぉ
+ dateValue.value = searchForm.value.timeStr
+ ? dayjs(searchForm.value.timeStr, 'YYYY-MM-DD').valueOf()
+ : Date.now()
+ showDatePicker.value = true
+}
+
+// 鏃ユ湡閫夋嫨纭锛堜笌鍏朵粬椤典竴鑷达細鎷挎椂闂存埑 -> YYYY-MM-DD锛�
+const onDateConfirm = (e) => {
+ searchForm.value.timeStr = formatDateToYMD(e.value)
+ showDatePicker.value = false
+ handleQuery()
+}
+
+// 鍝嶅簲寮忔暟鎹�
+const tableData = ref([])
+const userList = ref([])
+const tableLoading = ref(false)
+const dialogFormVisible = ref(false)
+const showDatePicker = ref(false)
+const showOutDatePicker = ref(false)
+const loadStatus = ref('loadmore')
+const dateValue = ref(new Date().getTime())
+
+const page = reactive({
+ current: 1,
+ size: 10,
+})
+
+const total = ref(0)
+const currentRowId = ref(null)
+const currentRowNum = ref(0)
+
+const data = reactive({
+ searchForm: {
+ supplierName: '',
+ timeStr: '',
+ },
+ form: {
+ inboundQuantity: '',
+ inboundTime: '',
+ nickName: '',
+ },
+ rules: {
+ inboundQuantity: [
+ { required: true, message: '璇疯緭鍏ュ嚭搴撴暟閲�', trigger: 'blur' },
+ {
+ validator: (rule, value, callback) => {
+ if (value && (value <= 0 || value > currentRowNum.value)) {
+ callback(new Error('璇峰~鍏ユ湁鏁堟暟瀛�'))
+ } else {
+ callback()
+ }
+ },
+ trigger: 'blur'
+ }
+ ],
+ inboundTime: [
+ { required: true, message: '璇烽�夋嫨鍑哄簱鏃ユ湡', trigger: 'change' }
+ ],
+ nickName: [
+ { required: true, message: '璇烽�夋嫨鍑哄簱浜�', trigger: 'change' }
+ ]
+ }
+})
+
+const { searchForm, form, rules } = toRefs(data)
+
+
+
+// 鏌ヨ鍒楄〃
+const handleQuery = () => {
+ page.current = 1
+ getList()
+}
+
+const getList = () => {
+ tableLoading.value = true
+ const params = {
+ ...page,
+ supplierName: searchForm.value.supplierName,
+ timeStr: searchForm.value.timeStr
+ }
+
+ getInPageByCustom(params).then(res => {
+ tableLoading.value = false
+ if (page.current === 1) {
+ tableData.value = res.data.records || []
+ } else {
+ tableData.value = [...tableData.value, ...(res.data.records || [])]
+ }
+ total.value = res.data.total || 0
+
+ // 鏇存柊鍔犺浇鐘舵��
+ if (tableData.value.length >= total.value) {
+ loadStatus.value = 'nomore'
+ } else {
+ loadStatus.value = 'loadmore'
+ }
+ }).catch(() => {
+ tableLoading.value = false
+ loadStatus.value = 'error'
+ })
+}
+
+// 鍔犺浇鏇村
+const loadMore = () => {
+ if (loadStatus.value === 'nomore') return
+
+ loadStatus.value = 'loading'
+ page.current++
+ getList()
+}
+
+// 鎵撳紑鍑哄簱琛ㄥ崟
+const openForm = async (row) => {
+ dialogFormVisible.value = true
+ currentRowId.value = row.id
+ currentRowNum.value = row.inboundNum || 0
+
+ // 鍒濆鍖栬〃鍗曟暟鎹�
+ form.value = {
+ inboundQuantity: '',
+ inboundTime: getCurrentDate(),
+ nickName: '',
+ }
+
+ // 鍔犺浇鐢ㄦ埛鍒楄〃
+ try {
+ const userLists = await userListNoPageByTenantId()
+ userList.value = userLists.data.map(item => ({
+ ...item,
+ label: item.nickName,
+ value: item.userId
+ }))
+ } catch (error) {
+ console.error('鍔犺浇鐢ㄦ埛鍒楄〃澶辫触:', error)
+ userList.value = []
+ }
+}
+
+// 鎻愪氦琛ㄥ崟
+const submitForm = () => {
+ proxy.$refs.formRef.validate().then(valid => {
+ if (valid && currentRowId.value) {
+ const outData = {
+ id: currentRowId.value,
+ salesLedgerProductId: 0,
+ quantity: form.value.inboundQuantity,
+ time: form.value.inboundTime,
+ userId: form.value.nickName,
+ type: 3 // 鑷畾涔夊嚭搴撶被鍨�
+ }
+
+ stockOut(outData).then(res => {
+ uni.$u.toast('鎻愪氦鎴愬姛')
+ closeDia()
+ getList()
+ }).catch(err => {
+ uni.$u.toast('鍑哄簱澶辫触')
+ })
+ }
+ }).catch(err => {
+ console.log('琛ㄥ崟楠岃瘉澶辫触:', err)
+ })
+}
+
+// 鍏抽棴寮圭獥
+const closeDia = () => {
+ dialogFormVisible.value = false
+ proxy.$refs.formRef.resetFields()
+}
+
+// 瀵煎嚭
+const handleOut = () => {
+ uni.showModal({
+ title: '瀵煎嚭',
+ content: '鏄惁纭瀵煎嚭锛�',
+ success: (res) => {
+ if (res.confirm) {
+ proxy.download("/stockin/exportTwo", {}, '鑷畾涔夊嚭搴撳彴璐�.xlsx')
+ }
+ }
+ })
+}
+
+// 鑾峰彇褰撳墠鏃ユ湡
+function getCurrentDate() {
+ const today = new Date()
+ const year = today.getFullYear()
+ const month = String(today.getMonth() + 1).padStart(2, '0')
+ const day = String(today.getDate()).padStart(2, '0')
+ return `${year}-${month}-${day}`
+}
+
+onMounted(() => {
+ getList()
+})
+</script>
+
+<style scoped lang="scss">
+.stock-out-page {
+ min-height: 100vh;
+ background: #f5f5f5;
+ padding-bottom: 80px;
+}
+
+.search-section {
+ background: #fff;
+ padding: 16px;
+ margin-bottom: 12px;
+}
+
+.search-bar {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ margin-bottom: 12px;
+}
+
+.search-input {
+ flex: 1;
+}
+
+.search-button {
+ width: 44px;
+ height: 44px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #f5f5f5;
+ border-radius: 8px;
+}
+
+.date-filter {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 12px 16px;
+ background: #f5f5f5;
+ border-radius: 8px;
+}
+
+.date-text {
+ font-size: 14px;
+ color: #666;
+}
+
+.stock-list {
+ padding: 0 16px;
+}
+
+.stock-item {
+ background: #fff;
+ border-radius: 12px;
+ padding: 16px;
+ margin-bottom: 12px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+}
+
+.item-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 12px;
+}
+
+.item-left {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.batch-icon {
+ width: 32px;
+ height: 32px;
+ background: #2979ff;
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.batch-text {
+ font-size: 14px;
+ font-weight: 500;
+ color: #333;
+}
+
+.time-text {
+ font-size: 12px;
+ color: #999;
+}
+
+.item-details {
+ margin: 12px 0;
+}
+
+.detail-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 8px 0;
+}
+
+.detail-label {
+ font-size: 14px;
+ color: #666;
+}
+
+.detail-value {
+ font-size: 14px;
+ color: #333;
+ text-align: right;
+ flex: 1;
+ margin-left: 12px;
+}
+
+.detail-value.highlight {
+ color: #2979ff;
+ font-weight: 500;
+}
+
+.detail-value.price {
+ color: #ff6b00;
+ font-weight: 500;
+}
+
+.item-actions {
+ display: flex;
+ gap: 12px;
+ margin-top: 12px;
+ padding-top: 12px;
+ border-top: 1px solid #f5f5f5;
+}
+
+.no-data {
+ text-align: center;
+ padding: 60px 0;
+ color: #999;
+ font-size: 14px;
+}
+
+.load-more {
+ padding: 20px 16px;
+}
+
+.popup-content {
+ width: 600rpx;
+ background: #ffffff;
+ border-radius: 20rpx;
+
+ .popup-header {
+ padding: 40rpx 30rpx 20rpx;
+ text-align: center;
+ border-bottom: 1rpx solid #f0f0f0;
+
+ .popup-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ color: #333;
+ }
+ }
+
+ .popup-body {
+ padding: 30rpx;
+ }
+
+ .popup-footer {
+ padding: 30rpx;
+ display: flex;
+ gap: 20rpx;
+ border-top: 1rpx solid #f0f0f0;
+
+ .u-button {
+ flex: 1;
+ }
+ }
+}
+</style>
--
Gitblit v1.9.3