From c46bf7475742e9b50a8fdcc8d592ba3a86b2754d Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 17 十一月 2025 15:02:25 +0800
Subject: [PATCH] 海川开心-添加请假管理、出差管理、公出管理页面
---
src/pages/cooperativeOffice/collaborativeApproval/approve.vue | 24
src/pages/index.vue | 116 +++
src/pages/inventoryManagement/receiptManagement/index.vue | 406 ++++++++++++++
src/pages/cooperativeOffice/collaborativeApproval/index1.vue | 17
src/pages.json | 35 +
src/pages/cooperativeOffice/collaborativeApproval/index3.vue | 17
src/pages/cooperativeOffice/collaborativeApproval/index.vue | 42 +
src/pages/cooperativeOffice/collaborativeApproval/detail.vue | 117 +++
src/pages/inventoryManagement/receiptManagement/components/formDiaManual.vue | 412 ++++++++++++++
src/api/inventoryManagement/stockIn.js | 130 ++++
src/pages/cooperativeOffice/collaborativeApproval/index2.vue | 17
src/pages/inventoryManagement/receiptManagement/detail.vue | 364 ++++++++++++
src/static/images/icon/gongchuguanli@2x.png | 0
src/pages/cooperativeOffice/collaborativeApproval/index4.vue | 17
src/static/images/icon/rukuguanli@2x.png | 0
src/static/images/icon/chuchaiguanli@2x.png | 0
src/static/images/icon/qingjiaguanli@2x.png | 0
17 files changed, 1,678 insertions(+), 36 deletions(-)
diff --git a/src/api/inventoryManagement/stockIn.js b/src/api/inventoryManagement/stockIn.js
new file mode 100644
index 0000000..d45eb1e
--- /dev/null
+++ b/src/api/inventoryManagement/stockIn.js
@@ -0,0 +1,130 @@
+import request from "@/utils/request";
+
+// 鏌ヨ鍏ュ簱淇℃伅鍒楄〃
+export const getStockInPage = (params) => {
+ return request({
+ url: "/stockin/listPage",
+ method: "get",
+ params,
+ });
+};
+
+// 鏌ヨ鐢熶骇鍏ュ簱淇℃伅鍒楄〃
+export const getStockInPageByProduction = (params) => {
+ return request({
+ url: "/stockin/listPageByProduction",
+ method: "get",
+ params,
+ });
+};
+
+// 鍑哄簱鍙拌处-鏌ヨ鑷畾涔夊叆搴撲俊鎭垪琛�
+export const getStockInPageByCustom = (params) => {
+ return request({
+ url: "/stockmanagement/listPageByCustom",
+ method: "get",
+ params,
+ });
+};
+// 鍏ュ簱绠$悊-鏌ヨ鑷畾涔夊叆搴撲俊鎭垪琛�
+export const getInPageByCustom = (params) => {
+ return request({
+ url: "/stockin/listPageByCustom",
+ method: "get",
+ params,
+ });
+};
+
+// 鍑哄簱鍙拌处-鏌ヨ鐢熶骇鍑哄簱淇℃伅鍒楄〃
+export const getStockInPageByProduct = (params) => {
+ return request({
+ url: "/stockmanagement/listPageByProduct",
+ method: "get",
+ params,
+ });
+};
+
+// 淇敼鍏ュ簱瀛樹俊鎭�
+export const updateStockIn = (data) => {
+ return request({
+ url: "/stockin/update",
+ method: "post",
+ data,
+ });
+};
+
+// 淇敼搴撳瓨淇℃伅
+export const updateManagement = (data) => {
+ return request({
+ url: "/stockin/updateManagement",
+ method: "post",
+ data,
+ });
+};
+
+// 鏂板鍟嗗搧鍏ュ簱淇℃伅
+export function addSutockIn(data) {
+ return request({
+ url: '/stockin/add',
+ method: 'post',
+ data: data
+ })
+}
+
+// 鏂板鑷畾涔夊叆搴撲俊鎭�
+export function addStockInCustom(data) {
+ return request({
+ url: '/stockin/addCustom',
+ method: 'post',
+ data: data
+ })
+}
+
+// 缂栬緫鑷畾涔夊叆搴撲俊鎭�
+export function updateStockInCustom(data) {
+ return request({
+ url: '/stockin/updateCustom',
+ method: 'post',
+ data: data
+ })
+}
+
+// 鍒犻櫎鍏ュ簱淇℃伅
+export function delStockIn(ids) {
+ return request({
+ url: '/stockin/del',
+ method: 'post',
+ data: ids
+ })
+}
+
+// 鍒犻櫎鑷畾涔夊叆搴撲俊鎭�
+export function delStockInCustom(ids) {
+ return request({
+ url: '/stockin/delteCustom',
+ method: 'post',
+ data: ids
+ })
+}
+
+// 瀵煎嚭鍏ュ簱淇℃伅
+export function exportStockIn(query) {
+ return request({
+ url: '/stockin/export',
+ method: 'get',
+ params: query,
+ responseType: 'blob'
+ })
+}
+
+export function selectProductRecordListByPuechaserId(query) {
+ return request({
+ url: '/stockin/productlist',
+ method: 'get',
+ params: query
+ })
+}
+
+
+//
+
diff --git a/src/pages.json b/src/pages.json
index 8aca2bc..654c337 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -247,6 +247,27 @@
}
},
{
+ "path": "pages/cooperativeOffice/collaborativeApproval/index1",
+ "style": {
+ "navigationBarTitleText": "鍏嚭绠$悊",
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/cooperativeOffice/collaborativeApproval/index2",
+ "style": {
+ "navigationBarTitleText": "璇峰亣绠$悊",
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/cooperativeOffice/collaborativeApproval/index3",
+ "style": {
+ "navigationBarTitleText": "鍑哄樊绠$悊",
+ "navigationStyle": "custom"
+ }
+ },
+ {
"path": "pages/cooperativeOffice/collaborativeApproval/index",
"style": {
"navigationBarTitleText": "瀹℃壒绠$悊",
@@ -434,6 +455,20 @@
"navigationBarTitleText": "鐢熶骇鏍哥畻",
"navigationStyle": "custom"
}
+ },
+ {
+ "path": "pages/inventoryManagement/receiptManagement/index",
+ "style": {
+ "navigationBarTitleText": "鑷畾涔夊叆搴�",
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/inventoryManagement/receiptManagement/detail",
+ "style": {
+ "navigationBarTitleText": "鏂板鍏ュ簱",
+ "navigationStyle": "custom"
+ }
}
],
"subPackages": [
diff --git a/src/pages/cooperativeOffice/collaborativeApproval/approve.vue b/src/pages/cooperativeOffice/collaborativeApproval/approve.vue
index f9e6ed2..aaad83e 100644
--- a/src/pages/cooperativeOffice/collaborativeApproval/approve.vue
+++ b/src/pages/cooperativeOffice/collaborativeApproval/approve.vue
@@ -25,6 +25,30 @@
<text class="info-label">鐢宠鏃ユ湡</text>
<text class="info-value">{{ approvalData.approveTime }}</text>
</view>
+
+ <!-- approveType=2 璇峰亣鐩稿叧瀛楁 -->
+ <template v-if="approvalData.approveType === 2">
+ <view class="info-row">
+ <text class="info-label">璇峰亣寮�濮嬫椂闂�</text>
+ <text class="info-value">{{ approvalData.startDate || '-' }}</text>
+ </view>
+ <view class="info-row">
+ <text class="info-label">璇峰亣缁撴潫鏃堕棿</text>
+ <text class="info-value">{{ approvalData.endDate || '-' }}</text>
+ </view>
+ </template>
+
+ <!-- approveType=3 鍑哄樊鐩稿叧瀛楁 -->
+ <view v-if="approvalData.approveType === 3" class="info-row">
+ <text class="info-label">鍑哄樊鍦扮偣</text>
+ <text class="info-value">{{ approvalData.location || '-' }}</text>
+ </view>
+
+ <!-- approveType=4 鎶ラ攢鐩稿叧瀛楁 -->
+ <view v-if="approvalData.approveType === 4" class="info-row">
+ <text class="info-label">鎶ラ攢閲戦</text>
+ <text class="info-value">{{ approvalData.price ? `楼${approvalData.price}` : '-' }}</text>
+ </view>
</view>
</view>
diff --git a/src/pages/cooperativeOffice/collaborativeApproval/detail.vue b/src/pages/cooperativeOffice/collaborativeApproval/detail.vue
index a564628..7dbf5b2 100644
--- a/src/pages/cooperativeOffice/collaborativeApproval/detail.vue
+++ b/src/pages/cooperativeOffice/collaborativeApproval/detail.vue
@@ -39,9 +39,48 @@
<u-form-item prop="approveTime" label="鐢宠鏃ユ湡" required>
<u-input
v-model="form.approveTime"
- placeholder="璇烽�夋嫨"
readonly
+ placeholder="璇烽�夋嫨"
@click="showDatePicker"
+ />
+ </u-form-item>
+
+ <!-- approveType=2 璇峰亣鐩稿叧瀛楁 -->
+ <template v-if="approveType === 2">
+ <u-form-item prop="startDate" label="璇峰亣寮�濮嬫椂闂�" required>
+ <u-input
+ v-model="form.startDate"
+ readonly
+ placeholder="璇烽�夋嫨寮�濮嬫椂闂�"
+ @click="showStartDatePicker"
+ />
+ </u-form-item>
+ <u-form-item prop="endDate" label="璇峰亣缁撴潫鏃堕棿" required>
+ <u-input
+ v-model="form.endDate"
+ readonly
+ placeholder="璇烽�夋嫨缁撴潫鏃堕棿"
+ @click="showEndDatePicker"
+ />
+ </u-form-item>
+ </template>
+
+ <!-- approveType=3 鍑哄樊鐩稿叧瀛楁 -->
+ <u-form-item v-if="approveType === 3" prop="location" label="鍑哄樊鍦扮偣" required>
+ <u-input
+ v-model="form.location"
+ placeholder="璇疯緭鍏ュ嚭宸湴鐐�"
+ clearable
+ />
+ </u-form-item>
+
+ <!-- approveType=4 鎶ラ攢鐩稿叧瀛楁 -->
+ <u-form-item v-if="approveType === 4" prop="price" label="鎶ラ攢閲戦" required>
+ <u-input
+ v-model="form.price"
+ type="number"
+ placeholder="璇疯緭鍏ユ姤閿�閲戦"
+ clearable
/>
</u-form-item>
</u-form>
@@ -56,15 +95,37 @@
/>
<!-- 鏃ユ湡閫夋嫨鍣� -->
- <u-popup v-model="showDate" mode="bottom">
- <u-datetime-picker
+ <up-popup :show="showDate" mode="bottom" @close="showDate = false">
+ <up-datetime-picker
+ :show="true"
v-model="currentDate"
- title="閫夋嫨鏃ユ湡"
- mode="date"
@confirm="onDateConfirm"
@cancel="showDate = false"
+ mode="date"
/>
- </u-popup>
+ </up-popup>
+
+ <!-- 璇峰亣寮�濮嬫椂闂撮�夋嫨鍣� -->
+ <up-popup :show="showStartDate" mode="bottom" @close="showStartDate = false">
+ <up-datetime-picker
+ :show="true"
+ v-model="startDateValue"
+ @confirm="onStartDateConfirm"
+ @cancel="showStartDate = false"
+ mode="date"
+ />
+ </up-popup>
+
+ <!-- 璇峰亣缁撴潫鏃堕棿閫夋嫨鍣� -->
+ <up-popup :show="showEndDate" mode="bottom" @close="showEndDate = false">
+ <up-datetime-picker
+ :show="true"
+ v-model="endDateValue"
+ @confirm="onEndDateConfirm"
+ @cancel="showEndDate = false"
+ mode="date"
+ />
+ </up-popup>
<!-- 瀹℃牳娴佺▼鍖哄煙 -->
<view class="approval-process">
<view class="approval-header">
@@ -137,7 +198,11 @@
approveReason: "",
checkResult: "",
tempFileIds: [],
- approverList: [] // 鏂板瀛楁锛屽瓨鍌ㄦ墍鏈夎妭鐐圭殑瀹℃壒浜篿d
+ approverList: [], // 鏂板瀛楁锛屽瓨鍌ㄦ墍鏈夎妭鐐圭殑瀹℃壒浜篿d
+ startDate: "",
+ endDate: "",
+ location: "",
+ price: ""
},
rules: {
approveTime: [{ required: false, message: "璇疯緭鍏�", trigger: "change" },],
@@ -145,6 +210,10 @@
approveDeptId: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
approveReason: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" }],
checkResult: [{ required: false, message: "璇疯緭鍏�", trigger: "blur" }],
+ startDate: [{ required: false, message: "璇烽�夋嫨寮�濮嬫椂闂�", trigger: "change" }],
+ endDate: [{ required: false, message: "璇烽�夋嫨缁撴潫鏃堕棿", trigger: "change" }],
+ location: [{ required: false, message: "璇疯緭鍏ュ嚭宸湴鐐�", trigger: "blur" }],
+ price: [{ required: false, message: "璇疯緭鍏ユ姤閿�閲戦", trigger: "blur" }],
},
});
const { form, rules } = toRefs(data);
@@ -158,8 +227,13 @@
const formRef = ref(null);
const message = ref("");
const showDate = ref(false)
-const currentDate = ref([new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()])
+const currentDate = ref(Date.now())
+const showStartDate = ref(false)
+const startDateValue = ref(Date.now())
+const showEndDate = ref(false)
+const endDateValue = ref(Date.now())
const userStore = useUserStore()
+const approveType = ref(0)
const getProductOptions = () => {
getDept().then((res) => {
@@ -184,6 +258,7 @@
// 浠庢湰鍦板瓨鍌ㄨ幏鍙栧弬鏁�
operationType.value = uni.getStorageSync('operationType') || 'add';
+ approveType.value = uni.getStorageSync('approveType') || 0;
// 濡傛灉鏄紪杈戞ā寮忥紝浠庢湰鍦板瓨鍌ㄨ幏鍙栨暟鎹�
if (operationType.value === 'edit') {
@@ -250,6 +325,7 @@
// 娓呴櫎鏈湴瀛樺偍鐨勬暟鎹�
uni.removeStorageSync('operationType');
uni.removeStorageSync('invoiceLedgerEditRow');
+ uni.removeStorageSync('approveType');
uni.navigateBack();
};
@@ -283,7 +359,7 @@
// 鏀堕泦鎵�鏈夎妭鐐圭殑瀹℃壒浜篿d
console.log('approverNodes---', approverNodes.value)
form.value.approveUserIds = approverNodes.value.map(node => node.userId).join(',')
- form.value.approveType = 0
+ form.value.approveType = approveType.value
if (operationType.value === "add" || currentApproveStatus.value == 3) {
approveProcessAdd(form.value).then(res => {
showToast("鎻愪氦鎴愬姛");
@@ -366,6 +442,28 @@
currentDate.value = formatDateToYMD(e.value)
showDate.value = false;
}
+
+// 鏄剧ず璇峰亣寮�濮嬫椂闂撮�夋嫨鍣�
+const showStartDatePicker = () => {
+ showStartDate.value = true
+}
+
+// 纭璇峰亣寮�濮嬫椂闂撮�夋嫨
+const onStartDateConfirm = (e) => {
+ form.value.startDate = formatDateToYMD(e.value)
+ showStartDate.value = false
+}
+
+const showEndDatePicker = () => {
+ showEndDate.value = true
+}
+
+// 纭璇峰亣缁撴潫鏃堕棿閫夋嫨
+const onEndDateConfirm = (e) => {
+ form.value.endDate = formatDateToYMD(e.value)
+ showEndDate.value = false
+}
+
// 鑾峰彇褰撳墠鏃ユ湡骞舵牸寮忓寲涓� YYYY-MM-DD
function getCurrentDate() {
const today = new Date();
@@ -374,6 +472,7 @@
const day = String(today.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
}
+
</script>
<style scoped lang="scss">
diff --git a/src/pages/cooperativeOffice/collaborativeApproval/index.vue b/src/pages/cooperativeOffice/collaborativeApproval/index.vue
index 8aab757..f72d200 100644
--- a/src/pages/cooperativeOffice/collaborativeApproval/index.vue
+++ b/src/pages/cooperativeOffice/collaborativeApproval/index.vue
@@ -55,6 +55,31 @@
<text class="detail-label">鐢宠鏃ユ湡</text>
<text class="detail-value">{{ item.approveTime }}</text>
</view>
+
+ <!-- approveType=2 璇峰亣鐩稿叧瀛楁 -->
+ <template v-if="item.approveType === 2">
+ <view class="detail-row">
+ <text class="detail-label">璇峰亣寮�濮嬫椂闂�</text>
+ <text class="detail-value">{{ item.startDate || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">璇峰亣缁撴潫鏃堕棿</text>
+ <text class="detail-value">{{ item.endDate || '-' }}</text>
+ </view>
+ </template>
+
+ <!-- approveType=3 鍑哄樊鐩稿叧瀛楁 -->
+ <view v-if="item.approveType === 3" class="detail-row">
+ <text class="detail-label">鍑哄樊鍦扮偣</text>
+ <text class="detail-value">{{ item.location || '-' }}</text>
+ </view>
+
+ <!-- approveType=4 鎶ラ攢鐩稿叧瀛楁 -->
+ <view v-if="item.approveType === 4" class="detail-row">
+ <text class="detail-label">鎶ラ攢閲戦</text>
+ <text class="detail-value highlightYellow">{{ item.price ? `楼${item.price}` : '-' }}</text>
+ </view>
+
<view class="detail-row">
<text class="detail-label">缁撴潫鏃ユ湡</text>
<text class="detail-value">{{ item.approveOverTime }}</text>
@@ -117,6 +142,14 @@
import {onShow} from "@dcloudio/uni-app";
import useUserStore from "@/store/modules/user";
+ // 鎺ユ敹鐖剁粍浠朵紶閫掔殑 approveType 鍙傛暟
+ const props = defineProps({
+ approveType: {
+ type: Number,
+ default: 0
+ }
+ });
+
const userStore = useUserStore()
// 鏁版嵁
const ledgerList = ref([]);
@@ -139,7 +172,7 @@
size: -1,
};
approveProcessListPage({
- ...page,approveType: 0,...searchForm.value
+ ...page,approveType: props.approveType,...searchForm.value
})
.then((res) => {
ledgerList.value = res.data.records;
@@ -206,6 +239,7 @@
uni.setStorageSync('invoiceLedgerEditRow', JSON.stringify(item));
uni.setStorageSync('operationType', 'edit');
uni.setStorageSync('approveId', item.approveId);
+ uni.setStorageSync('approveType', props.approveType);
uni.navigateTo({
url: "/pages/cooperativeOffice/collaborativeApproval/detail",
});
@@ -214,15 +248,17 @@
// 娣诲姞鏂拌褰�
const handleAdd = () => {
uni.setStorageSync('operationType', 'add');
+ uni.setStorageSync('approveType', props.approveType);
uni.navigateTo({
- url: "/pages/cooperativeOffice/collaborativeApproval/detail",
+ url: `/pages/cooperativeOffice/collaborativeApproval/detail?approveType=${props.approveType}`,
});
};
// 鐐瑰嚮瀹℃牳
const approve = (item) => {
uni.setStorageSync('approveId', item.approveId);
+ uni.setStorageSync('approveType', props.approveType);
uni.navigateTo({
- url: "/pages/cooperativeOffice/collaborativeApproval/approve"
+ url: "/pages/cooperativeOffice/collaborativeApproval/approve?approveType=" + props.approveType
})
}
diff --git a/src/pages/cooperativeOffice/collaborativeApproval/index1.vue b/src/pages/cooperativeOffice/collaborativeApproval/index1.vue
new file mode 100644
index 0000000..dc70530
--- /dev/null
+++ b/src/pages/cooperativeOffice/collaborativeApproval/index1.vue
@@ -0,0 +1,17 @@
+<template>
+ <view class="container">
+ <!-- 寮曞叆index.vue缁勪欢骞朵紶閫掑弬鏁� -->
+ <ApprovalProcessIndex :approveType="1" />
+ </view>
+</template>
+
+<script setup>
+import ApprovalProcessIndex from './index.vue'
+</script>
+
+<style scoped>
+.container {
+ width: 100%;
+ height: 100%;
+}
+</style>
diff --git a/src/pages/cooperativeOffice/collaborativeApproval/index2.vue b/src/pages/cooperativeOffice/collaborativeApproval/index2.vue
new file mode 100644
index 0000000..6da82b3
--- /dev/null
+++ b/src/pages/cooperativeOffice/collaborativeApproval/index2.vue
@@ -0,0 +1,17 @@
+<template>
+ <view class="container">
+ <!-- 寮曞叆index.vue缁勪欢骞朵紶閫掑弬鏁� -->
+ <ApprovalProcessIndex :approveType="2" />
+ </view>
+</template>
+
+<script setup>
+import ApprovalProcessIndex from './index.vue'
+</script>
+
+<style scoped>
+.container {
+ width: 100%;
+ height: 100%;
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/cooperativeOffice/collaborativeApproval/index3.vue b/src/pages/cooperativeOffice/collaborativeApproval/index3.vue
new file mode 100644
index 0000000..8a4b231
--- /dev/null
+++ b/src/pages/cooperativeOffice/collaborativeApproval/index3.vue
@@ -0,0 +1,17 @@
+<template>
+ <view class="container">
+ <!-- 寮曞叆index.vue缁勪欢骞朵紶閫掑弬鏁� -->
+ <ApprovalProcessIndex :approveType="3" />
+ </view>
+</template>
+
+<script setup>
+import ApprovalProcessIndex from './index.vue'
+</script>
+
+<style scoped>
+.container {
+ width: 100%;
+ height: 100%;
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/cooperativeOffice/collaborativeApproval/index4.vue b/src/pages/cooperativeOffice/collaborativeApproval/index4.vue
new file mode 100644
index 0000000..fc75609
--- /dev/null
+++ b/src/pages/cooperativeOffice/collaborativeApproval/index4.vue
@@ -0,0 +1,17 @@
+<template>
+ <view class="container">
+ <!-- 寮曞叆index.vue缁勪欢骞朵紶閫掑弬鏁� -->
+ <ApprovalProcessIndex :approveType="4" />
+ </view>
+</template>
+
+<script setup>
+import ApprovalProcessIndex from './index.vue'
+</script>
+
+<style scoped>
+.container {
+ width: 100%;
+ height: 100%;
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/index.vue b/src/pages/index.vue
index 7922cc1..04da41f 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -121,6 +121,35 @@
</up-grid>
</view>
</view>
+ <!-- 鍏ュ簱绠$悊 -->
+ <view class="common-module collaboration-module">
+ <view class="module-header">
+ <view class="module-title-container">
+ <text class="module-title">鍏ュ簱绠$悊</text>
+ </view>
+ </view>
+ <view class="module-content">
+ <up-grid
+ :border="false"
+ col="4"
+ >
+ <up-grid-item
+ v-for="(item, index) in inventoryManagement"
+ :key="index"
+ @click="handleCommonItemClick(item)"
+ >
+ <view class="icon-container" :style="{ background: item.bgColor }">
+ <up-icon
+ :name="item.icon"
+ :size="58"
+ color="#ffffff"
+ ></up-icon>
+ </view>
+ <text class="item-label">{{item.label}}</text>
+ </up-grid-item>
+ </up-grid>
+ </view>
+ </view>
<!-- 鐢熶骇绠℃帶妯″潡 -->
<view class="common-module production-module">
@@ -273,6 +302,18 @@
// 鍗忓悓鍔炲叕鍔熻兘鏁版嵁
const collaborationItems = reactive([
{
+ icon: '/static/images/icon/gongchuguanli@2x.png',
+ label: '鍏嚭绠$悊',
+ },
+ {
+ icon: '/static/images/icon/qingjiaguanli@2x.png',
+ label: '璇峰亣绠$悊',
+ },
+ {
+ icon: '/static/images/icon/chuchaiguanli@2x.png',
+ label: '鍑哄樊绠$悊',
+ },
+ {
icon: '/static/images/icon/xietongshenpi@2x.png',
label: '鍗忓悓瀹℃壒',
},
@@ -280,6 +321,13 @@
icon: '/static/images/icon/kehubaifang@2x.png',
label: '瀹㈡埛鎷滆',
}
+]);
+// 鍗忓悓鍔炲叕鍔熻兘鏁版嵁inventoryManagement/receiptManagement
+const inventoryManagement = reactive([
+ {
+ icon: '/static/images/icon/rukuguanli@2x.png',
+ label: '鑷畾涔夊叆搴�',
+ },
]);
// 鐢熶骇绠℃帶鍔熻兘鏁版嵁
@@ -313,10 +361,10 @@
// 璁惧绠$悊鍔熻兘鏁版嵁
const equipmentItems = reactive([
- // {
- // icon: '/static/images/icon/shebeitaizhang@2x.png',
- // label: '璁惧鍙拌处',
- // },
+ {
+ icon: '/static/images/icon/shebeitaizhang@2x.png',
+ label: '璁惧鍙拌处',
+ },
{
icon: '/static/images/icon/shbeibaoxiu@2x.png',
label: '璁惧鎶ヤ慨',
@@ -329,26 +377,26 @@
icon: '/static/images/icon/xunjianshangchuan@2x.png',
label: '宸℃涓婁紶',
},
- {
- icon: '/static/images/icon/guzhangfenxi@2x.png',
- label: '鍒嗘瀽杩芥函',
- bgColor: '#ff9800'
- },
- {
- icon: '/static/images/icon/zhinengpaidan@2x.png',
- label: '鏅鸿兘娲惧崟',
- bgColor: '#ff6b35'
- },
- {
- icon: '/static/images/icon/zuoyezhidao@2x.png',
- label: '浣滀笟鎸囧',
- bgColor: '#4caf50'
- },
- {
- icon: '/static/images/icon/jieguoyanzheng@2x.png',
- label: '缁撴灉楠岃瘉',
- bgColor: '#9c27b0'
- }
+ // {
+ // icon: '/static/images/icon/guzhangfenxi@2x.png',
+ // label: '鍒嗘瀽杩芥函',
+ // bgColor: '#ff9800'
+ // },
+ // {
+ // icon: '/static/images/icon/zhinengpaidan@2x.png',
+ // label: '鏅鸿兘娲惧崟',
+ // bgColor: '#ff6b35'
+ // },
+ // {
+ // icon: '/static/images/icon/zuoyezhidao@2x.png',
+ // label: '浣滀笟鎸囧',
+ // bgColor: '#4caf50'
+ // },
+ // {
+ // icon: '/static/images/icon/jieguoyanzheng@2x.png',
+ // label: '缁撴灉楠岃瘉',
+ // bgColor: '#9c27b0'
+ // }
]);
// 澶勭悊甯哥敤鍔熻兘鐐瑰嚮
@@ -415,6 +463,21 @@
url: '/pages/procurementManagement/paymentLedger/index'
});
break;
+ case '鍏嚭绠$悊':
+ uni.navigateTo({
+ url: '/pages/cooperativeOffice/collaborativeApproval/index1'
+ });
+ break;
+ case '璇峰亣绠$悊':
+ uni.navigateTo({
+ url: '/pages/cooperativeOffice/collaborativeApproval/index2'
+ });
+ break;
+ case '鍑哄樊绠$悊':
+ uni.navigateTo({
+ url: '/pages/cooperativeOffice/collaborativeApproval/index3'
+ });
+ break;
case '鍗忓悓瀹℃壒':
uni.navigateTo({
url: '/pages/cooperativeOffice/collaborativeApproval/index'
@@ -425,6 +488,11 @@
url: '/pages/cooperativeOffice/clientVisit/index'
});
break;
+ case '鑷畾涔夊叆搴�':
+ uni.navigateTo({
+ url: '/pages/inventoryManagement/receiptManagement/index'
+ });
+ break;
case '鐢熶骇璁㈠崟':
uni.navigateTo({
url: '/pages/productionManagement/productionOrder/index'
diff --git a/src/pages/inventoryManagement/receiptManagement/components/formDiaManual.vue b/src/pages/inventoryManagement/receiptManagement/components/formDiaManual.vue
new file mode 100644
index 0000000..f973f6b
--- /dev/null
+++ b/src/pages/inventoryManagement/receiptManagement/components/formDiaManual.vue
@@ -0,0 +1,412 @@
+锘�<template>
+ <up-popup :show="dialogFormVisible" mode="bottom" :round="10" closeable @close="closeDia">
+ <view class="form-popup">
+ <view class="popup-header">
+ <text class="popup-title">{{ operationType === 'add' ? '鏂板鑷畾涔夊叆搴�' : '缂栬緫鑷畾涔夊叆搴�' }}</text>
+ </view>
+
+ <scroll-view class="popup-content" scroll-y>
+ <view v-if="operationType === 'add'" class="add-btn-section">
+ <u-button type="primary" @click="addProductRow">鏂板浜у搧</u-button>
+ </view>
+
+ <view v-for="(item, index) in productList" :key="index" class="product-item">
+ <view class="item-header">
+ <text class="item-title">浜у搧 {{ index + 1 }}</text>
+ <u-button v-if="operationType === 'add'" type="error" size="mini" class="delete-btn" @click="removeProductRow(index)">鍒犻櫎</u-button>
+ </view>
+
+ <view class="item-form">
+ <view class="form-field">
+ <text class="field-label required">浜у搧澶х被</text>
+ <up-input v-model="item.productCategory" placeholder="璇疯緭鍏ヤ骇鍝佸ぇ绫�" />
+ </view>
+
+ <view class="form-field">
+ <text class="field-label required">瑙勬牸鍨嬪彿</text>
+ <up-input v-model="item.specificationModel" placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�" />
+ </view>
+
+ <view class="form-field">
+ <text class="field-label required">鍗曚綅</text>
+ <up-input v-model="item.unit" placeholder="璇疯緭鍏ュ崟浣�" />
+ </view>
+
+ <view class="form-field">
+ <text class="field-label">渚涘簲鍟�</text>
+ <up-input v-model="item.supplierName" placeholder="璇疯緭鍏ヤ緵搴斿晢" />
+ </view>
+
+ <view class="form-field">
+ <text class="field-label required">鐗╁搧绫诲瀷</text>
+ <up-input v-model="item.itemType" readonly placeholder="璇烽�夋嫨鐗╁搧绫诲瀷" @click="openItemTypePicker(index)" />
+ </view>
+
+ <view class="form-field">
+ <text class="field-label required">鍏ュ簱鏁伴噺</text>
+ <up-input v-model="item.inboundNum" type="number" placeholder="璇疯緭鍏ュ叆搴撴暟閲�" @blur="calculateTotalPrice(item)" />
+ </view>
+
+ <view class="form-field">
+ <text class="field-label required">鍏ュ簱鏃ユ湡</text>
+ <up-input v-model="item.inboundDate" readonly placeholder="璇烽�夋嫨鍏ュ簱鏃ユ湡" @click="openDatePicker(index)" />
+ </view>
+
+ <view class="form-field">
+ <text class="field-label">绋庣巼(%)</text>
+ <up-input v-model="item.taxRate" readonly placeholder="璇烽�夋嫨绋庣巼" @click="openTaxRatePicker(index)" />
+ </view>
+
+ <view class="form-field">
+ <text class="field-label">鍚◣鍗曚环(鍏�)</text>
+ <up-input v-model="item.taxInclusiveUnitPrice" type="digit" placeholder="璇疯緭鍏ュ惈绋庡崟浠�" @blur="calculateTotalPrice(item)" />
+ </view>
+
+ <view class="form-field">
+ <text class="field-label">鍚◣鎬讳环(鍏�)</text>
+ <up-input v-model="item.taxInclusiveTotalPrice" type="digit" placeholder="鑷姩璁$畻" @blur="calculateExclusivePrice(item)" />
+ </view>
+
+ <view class="form-field">
+ <text class="field-label">涓嶅惈绋庢�讳环(鍏�)</text>
+ <up-input v-model="item.taxExclusiveTotalPrice" type="digit" placeholder="鑷姩璁$畻" disabled />
+ </view>
+ </view>
+ </view>
+ </scroll-view>
+
+ <view class="popup-footer">
+ <u-button class="btn-cancel" @click="closeDia">鍙栨秷</u-button>
+ <u-button class="btn-confirm" type="primary" @click="submitForm">纭</u-button>
+ </view>
+ </view>
+
+ <up-action-sheet :show="showItemTypePicker" :actions="itemTypeActions" title="閫夋嫨鐗╁搧绫诲瀷" @select="onItemTypeSelect" @close="showItemTypePicker = false" />
+ <up-action-sheet :show="showTaxRatePicker" :actions="taxRateActions" title="閫夋嫨绋庣巼" @select="onTaxRateSelect" @close="showTaxRatePicker = false" />
+ <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>
+ </up-popup>
+</template>
+
+<script setup>
+import { ref, reactive, toRefs } from 'vue'
+import useUserStore from '@/store/modules/user'
+import { formatDateToYMD } from '@/utils/ruoyi'
+import { addStockInCustom, updateStockInCustom } from '@/api/inventoryManagement/stockIn.js'
+
+const userStore = useUserStore()
+const emit = defineEmits(['close', 'success'])
+
+const operationType = ref('')
+const dialogFormVisible = ref(false)
+const productList = ref([])
+const loading = ref(false)
+
+const showItemTypePicker = ref(false)
+const showTaxRatePicker = ref(false)
+const showDatePicker = ref(false)
+const dateValue = ref(new Date().getTime())
+const currentEditIndex = ref(0)
+
+function formatDateTime(date = new Date(), includeTime = true) {
+ const d = new Date(date)
+ const year = d.getFullYear()
+ const month = String(d.getMonth() + 1).padStart(2, '0')
+ const day = String(d.getDate()).padStart(2, '0')
+ if (!includeTime) return `${year}-${month}-${day}`
+ const hours = String(d.getHours()).padStart(2, '0')
+ const minutes = String(d.getMinutes()).padStart(2, '0')
+ const seconds = String(d.getSeconds()).padStart(2, '0')
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+}
+
+function getCurrentDate() {
+ return formatDateTime(new Date(), false)
+}
+
+const itemTypeActions = ref([
+ { name: '鐗╂枡', value: '鐗╂枡' },
+ { name: '鍘熸枡', value: '鍘熸枡' },
+ { name: '鎴愬搧', value: '鎴愬搧' },
+ { name: '鍏朵粬', value: '鍏朵粬' }
+])
+
+const taxRateActions = ref([
+ { name: '1%', value: 1 },
+ { name: '6%', value: 6 },
+ { name: '13%', value: 13 }
+])
+
+const data = reactive({
+ form: {
+ id: null,
+ supplierId: null,
+ supplierName: '',
+ recorderId: userStore.userId,
+ recorderName: userStore.name,
+ entryDate: getCurrentDate(),
+ remark: ''
+ }
+})
+const { form } = toRefs(data)
+
+const addProductRow = () => {
+ productList.value.push({
+ id: null,
+ productCategory: '',
+ specificationModel: '',
+ unit: '',
+ supplierName: form.value.supplierName || '',
+ itemType: '',
+ inboundNum: 0,
+ inboundDate: '',
+ taxRate: null,
+ taxInclusiveUnitPrice: 0,
+ taxInclusiveTotalPrice: 0,
+ taxExclusiveTotalPrice: 0
+ })
+}
+
+const removeProductRow = (index) => {
+ productList.value.splice(index, 1)
+}
+
+const openItemTypePicker = (index) => {
+ currentEditIndex.value = index
+ showItemTypePicker.value = true
+}
+
+const onItemTypeSelect = (item) => {
+ productList.value[currentEditIndex.value].itemType = item.value
+ showItemTypePicker.value = false
+}
+
+const openTaxRatePicker = (index) => {
+ currentEditIndex.value = index
+ showTaxRatePicker.value = true
+}
+
+const onTaxRateSelect = (item) => {
+ productList.value[currentEditIndex.value].taxRate = item.value
+ calculateExclusivePrice(productList.value[currentEditIndex.value])
+ showTaxRatePicker.value = false
+}
+
+const openDatePicker = (index) => {
+ currentEditIndex.value = index
+ showDatePicker.value = true
+}
+
+const onDateConfirm = (e) => {
+ productList.value[currentEditIndex.value].inboundDate = formatDateToYMD(e.value)
+ showDatePicker.value = false
+}
+
+const calculateTotalPrice = (row) => {
+ const unitPrice = Number(row.taxInclusiveUnitPrice || 0)
+ const quantity = Number(row.inboundNum || 0)
+ row.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2)
+ calculateExclusivePrice(row)
+}
+
+const calculateExclusivePrice = (row) => {
+ const totalPrice = Number(row.taxInclusiveTotalPrice || 0)
+ const taxRate = Number(row.taxRate || 0)
+ row.taxExclusiveTotalPrice = (totalPrice / (1 + taxRate / 100)).toFixed(2)
+}
+
+const submitForm = async () => {
+ try {
+ if (!productList.value.length) {
+ uni.showToast({ title: '璇疯嚦灏戞坊鍔犱竴鏉′骇鍝佹暟鎹�', icon: 'none' })
+ return
+ }
+ for (let i = 0; i < productList.value.length; i++) {
+ const product = productList.value[i]
+ if (!product.productCategory || !product.specificationModel || !product.unit) {
+ uni.showToast({ title: 绗浜у搧鏁版嵁鏈~鍐欏畬鏁�, icon: 'none' })
+ return
+ }
+ if (!product.itemType) {
+ uni.showToast({ title: 绗璇烽�夋嫨鐗╁搧绫诲瀷, icon: 'none' })
+ return
+ }
+ if (!product.inboundDate) {
+ uni.showToast({ title: 绗璇烽�夋嫨鍏ュ簱鏃ユ湡, icon: 'none' })
+ return
+ }
+ const stock = Number(product?.inboundNum ?? 0)
+ if (!Number.isFinite(stock) || stock <= 0) {
+ uni.showToast({ title: 绗鍏ュ簱鏁伴噺闇�澶т簬0, icon: 'none' })
+ return
+ }
+ }
+ const payloadList = productList.value.map(product => ({
+ id: product.id ?? null,
+ inboundNum: Number(product.inboundNum),
+ productCategory: product.productCategory,
+ specificationModel: product.specificationModel,
+ unit: product.unit,
+ supplierName: product.supplierName || form.value.supplierName,
+ itemType: product.itemType,
+ inboundDate: formatDateTime(product.inboundDate, false),
+ taxRate: Number(product.taxRate || 0),
+ taxInclusiveUnitPrice: Number(product.taxInclusiveUnitPrice || 0),
+ taxInclusiveTotalPrice: Number(product.taxInclusiveTotalPrice || 0),
+ taxExclusiveTotalPrice: Number(product.taxExclusiveTotalPrice || 0)
+ }))
+ loading.value = true
+ uni.showLoading({ title: '鎻愪氦涓�...', mask: true })
+ if (operationType.value === 'edit') {
+ await updateStockInCustom(payloadList[0])
+ } else {
+ await addStockInCustom(payloadList)
+ }
+ uni.hideLoading()
+ uni.showToast({ title: operationType.value === 'edit' ? '缂栬緫鎴愬姛' : '鏂板鎴愬姛', icon: 'success' })
+ closeDia()
+ emit('success')
+ } catch (error) {
+ console.error('鎻愪氦澶辫触:', error)
+ uni.hideLoading()
+ uni.showToast({ title: '鎿嶄綔澶辫触锛岃閲嶈瘯', icon: 'none' })
+ } finally {
+ loading.value = false
+ }
+}
+
+const closeDia = () => {
+ dialogFormVisible.value = false
+ productList.value = []
+ emit('close')
+}
+
+const openDialog = async (type, row) => {
+ operationType.value = type
+ dialogFormVisible.value = true
+ if (type === 'add') {
+ form.value = {
+ id: null,
+ supplierId: null,
+ supplierName: '',
+ recorderId: userStore.userId,
+ recorderName: userStore.name,
+ entryDate: getCurrentDate(),
+ remark: ''
+ }
+ productList.value = []
+ } else {
+ form.value = {
+ id: row?.id ?? null,
+ supplierId: row?.supplierId ?? null,
+ supplierName: row?.supplierName ?? '',
+ recorderId: userStore.userId,
+ recorderName: userStore.name,
+ entryDate: getCurrentDate(),
+ remark: row?.remark ?? ''
+ }
+ productList.value = [{
+ id: row?.id ?? null,
+ productCategory: row?.productCategory ?? '',
+ specificationModel: row?.specificationModel ?? '',
+ unit: row?.unit ?? '',
+ supplierName: row?.supplierName ?? '',
+ itemType: row?.itemType ?? '',
+ inboundNum: Number(row?.inboundNum ?? row?.inboundQuantity ?? 0),
+ inboundDate: row?.inboundDate ?? row?.createTime ?? '',
+ taxRate: Number(row?.taxRate ?? 0),
+ taxInclusiveUnitPrice: Number(row?.taxInclusiveUnitPrice ?? 0),
+ taxInclusiveTotalPrice: Number(row?.taxInclusiveTotalPrice ?? 0),
+ taxExclusiveTotalPrice: Number(row?.taxExclusiveTotalPrice ?? 0)
+ }]
+ }
+}
+
+defineExpose({ openDialog })
+</script>
+
+<style scoped lang="scss">
+.form-popup {
+ height: 80vh;
+ display: flex;
+ flex-direction: column;
+ background: #f5f5f5;
+}
+.popup-header {
+ padding: 16px;
+ background: #fff;
+ border-bottom: 1px solid #f0f0f0;
+}
+.popup-title {
+ font-size: 18px;
+ font-weight: 600;
+ color: #333;
+}
+.popup-content {
+ flex: 1;
+ height: 0;
+ padding: 12px;
+}
+.add-btn-section {
+ margin-bottom: 12px;
+}
+.product-item {
+ background: #fff;
+ border-radius: 12px;
+ margin-bottom: 12px;
+ overflow: hidden;
+}
+.item-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 12px 16px;
+ background: #f8f8f8;
+ border-bottom: 1px solid #f0f0f0;
+}
+.item-title {
+ font-size: 16px;
+ font-weight: 600;
+ width: 100%;
+ color: #333;
+}
+.item-form {
+ padding: 16px;
+}
+.form-field {
+ margin-bottom: 16px;
+}
+.field-label {
+ display: block;
+ font-size: 14px;
+ color: #666;
+ margin-bottom: 8px;
+}
+.field-label.required::before {
+ content: '*';
+ color: #ff0000;
+ margin-right: 4px;
+}
+.popup-footer {
+ display: flex;
+ gap: 12px;
+ padding: 12px 16px;
+ background: #fff;
+ border-top: 1px solid #f0f0f0;
+}
+.btn-cancel, .btn-confirm {
+ flex: 1;
+}
+.btn-cancel {
+ background: #f5f5f5;
+ color: #666;
+ border: none;
+}
+.delete-btn {
+ padding: 2px 8px !important;
+ height: 24px !important;
+ font-size: 11px !important;
+ width: 20px !important;
+}
+</style>
diff --git a/src/pages/inventoryManagement/receiptManagement/detail.vue b/src/pages/inventoryManagement/receiptManagement/detail.vue
new file mode 100644
index 0000000..241a0ff
--- /dev/null
+++ b/src/pages/inventoryManagement/receiptManagement/detail.vue
@@ -0,0 +1,364 @@
+<template>
+ <view class="stock-detail-page">
+ <PageHeader :title="operationType === 'add' ? '鏂板鍏ュ簱' : '缂栬緫鍏ュ簱'" @back="goBack" />
+
+ <u-form ref="formRef" :model="form" :rules="rules" label-width="140rpx">
+ <!-- 鍩烘湰淇℃伅 -->
+ <view class="form-section">
+ <view class="section-title">鍩烘湰淇℃伅</view>
+
+ <u-form-item prop="supplierName" label="渚涘簲鍟�" required>
+ <u-input
+ v-model="form.supplierName"
+ placeholder="璇疯緭鍏ヤ緵搴斿晢鍚嶇О"
+ clearable
+ />
+ </u-form-item>
+
+ <u-form-item prop="productCategory" label="浜у搧澶х被" required>
+ <u-input
+ v-model="form.productCategory"
+ placeholder="璇疯緭鍏ヤ骇鍝佸ぇ绫�"
+ clearable
+ />
+ </u-form-item>
+
+ <u-form-item prop="specificationModel" label="瑙勬牸鍨嬪彿" required>
+ <u-input
+ v-model="form.specificationModel"
+ placeholder="璇疯緭鍏ヨ鏍煎瀷鍙�"
+ clearable
+ />
+ </u-form-item>
+
+ <u-form-item prop="unit" label="鍗曚綅" required>
+ <u-input
+ v-model="form.unit"
+ placeholder="璇疯緭鍏ュ崟浣�"
+ clearable
+ />
+ </u-form-item>
+
+ <u-form-item prop="itemType" label="鐗╁搧绫诲瀷" required>
+ <u-input
+ v-model="form.itemType"
+ readonly
+ placeholder="璇烽�夋嫨鐗╁搧绫诲瀷"
+ @click="showItemTypePicker = true"
+ />
+ <template #right>
+ <up-icon name="arrow-right" @click="showItemTypePicker = true"></up-icon>
+ </template>
+ </u-form-item>
+
+ <u-form-item prop="inboundDate" label="鍏ュ簱鏃ユ湡" required>
+ <u-input
+ v-model="form.inboundDate"
+ readonly
+ placeholder="璇烽�夋嫨鍏ュ簱鏃ユ湡"
+ @click="showDatePicker = true"
+ />
+ <template #right>
+ <up-icon name="calendar" @click="showDatePicker = true"></up-icon>
+ </template>
+ </u-form-item>
+ </view>
+
+ <!-- 鏁伴噺鍜屼环鏍� -->
+ <view class="form-section">
+ <view class="section-title">鏁伴噺鍜屼环鏍�</view>
+
+ <u-form-item prop="inboundNum" label="鍏ュ簱鏁伴噺" required>
+ <u-input
+ v-model="form.inboundNum"
+ type="number"
+ placeholder="璇疯緭鍏ュ叆搴撴暟閲�"
+ @blur="calculateTotalPrice"
+ />
+ </u-form-item>
+
+ <u-form-item prop="taxInclusiveUnitPrice" label="鍚◣鍗曚环" required>
+ <u-input
+ v-model="form.taxInclusiveUnitPrice"
+ type="digit"
+ placeholder="璇疯緭鍏ュ惈绋庡崟浠�"
+ @blur="calculateTotalPrice"
+ />
+ </u-form-item>
+
+ <u-form-item prop="taxInclusiveTotalPrice" label="鍚◣鎬讳环">
+ <u-input
+ v-model="form.taxInclusiveTotalPrice"
+ type="digit"
+ placeholder="鑷姩璁$畻"
+ disabled
+ />
+ </u-form-item>
+
+ <u-form-item prop="taxRate" label="绋庣巼(%)" required>
+ <u-input
+ v-model="form.taxRate"
+ readonly
+ placeholder="璇烽�夋嫨绋庣巼"
+ @click="showTaxRatePicker = true"
+ />
+ <template #right>
+ <up-icon name="arrow-right" @click="showTaxRatePicker = true"></up-icon>
+ </template>
+ </u-form-item>
+
+ <u-form-item prop="taxExclusiveTotalPrice" label="涓嶅惈绋庢�讳环">
+ <u-input
+ v-model="form.taxExclusiveTotalPrice"
+ type="digit"
+ placeholder="鑷姩璁$畻"
+ disabled
+ />
+ </u-form-item>
+ </view>
+ </u-form>
+
+ <!-- 搴曢儴鎸夐挳 -->
+ <view class="footer-btns">
+ <u-button class="cancel-btn" @click="goBack">鍙栨秷</u-button>
+ <u-button class="save-btn" @click="submitForm">淇濆瓨</u-button>
+ </view>
+
+ <!-- 鐗╁搧绫诲瀷閫夋嫨鍣� -->
+ <up-action-sheet
+ :show="showItemTypePicker"
+ :actions="itemTypeOptions"
+ title="閫夋嫨鐗╁搧绫诲瀷"
+ @select="onItemTypeSelect"
+ @close="showItemTypePicker = false"
+ />
+
+ <!-- 绋庣巼閫夋嫨鍣� -->
+ <up-action-sheet
+ :show="showTaxRatePicker"
+ :actions="taxRateOptions"
+ title="閫夋嫨绋庣巼"
+ @select="onTaxRateSelect"
+ @close="showTaxRatePicker = false"
+ />
+
+ <!-- 鏃ユ湡閫夋嫨鍣� -->
+ <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>
+</template>
+
+<script setup>
+import { ref, reactive, toRefs, onMounted } from 'vue'
+import { onLoad } from '@dcloudio/uni-app'
+import PageHeader from '@/components/PageHeader.vue'
+import { formatDateToYMD } from '@/utils/ruoyi'
+import {
+ addStockInCustom,
+ updateStockInCustom
+} from "@/api/inventoryManagement/stockIn.js"
+
+const formRef = ref(null)
+const operationType = ref('add')
+const showItemTypePicker = ref(false)
+const showTaxRatePicker = ref(false)
+const showDatePicker = ref(false)
+const dateValue = ref(new Date().getTime())
+
+const data = reactive({
+ form: {
+ supplierName: '',
+ productCategory: '',
+ specificationModel: '',
+ unit: '',
+ itemType: '',
+ inboundDate: '',
+ inboundNum: '',
+ taxInclusiveUnitPrice: '',
+ taxInclusiveTotalPrice: '',
+ taxRate: '',
+ taxExclusiveTotalPrice: '',
+ },
+ rules: {
+ supplierName: [{ required: true, message: '璇疯緭鍏ヤ緵搴斿晢鍚嶇О', trigger: 'blur' }],
+ productCategory: [{ required: true, message: '璇疯緭鍏ヤ骇鍝佸ぇ绫�', trigger: 'blur' }],
+ specificationModel: [{ required: true, message: '璇疯緭鍏ヨ鏍煎瀷鍙�', trigger: 'blur' }],
+ unit: [{ required: true, message: '璇疯緭鍏ュ崟浣�', trigger: 'blur' }],
+ itemType: [{ required: true, message: '璇烽�夋嫨鐗╁搧绫诲瀷', trigger: 'change' }],
+ inboundDate: [{ required: true, message: '璇烽�夋嫨鍏ュ簱鏃ユ湡', trigger: 'change' }],
+ inboundNum: [{ required: true, message: '璇疯緭鍏ュ叆搴撴暟閲�', trigger: 'blur' }],
+ taxInclusiveUnitPrice: [{ required: true, message: '璇疯緭鍏ュ惈绋庡崟浠�', trigger: 'blur' }],
+ taxRate: [{ required: true, message: '璇烽�夋嫨绋庣巼', trigger: 'change' }],
+ },
+})
+const { form, rules } = toRefs(data)
+
+// 鐗╁搧绫诲瀷閫夐」
+const itemTypeOptions = ref([
+ { name: '鍘熸潗鏂�', value: '鍘熸潗鏂�' },
+ { name: '鍗婃垚鍝�', value: '鍗婃垚鍝�' },
+ { name: '鎴愬搧', value: '鎴愬搧' },
+ { name: '杈呮枡', value: '杈呮枡' },
+ { name: '鍖呰鐗�', value: '鍖呰鐗�' },
+ { name: '鍏朵粬', value: '鍏朵粬' },
+])
+
+// 绋庣巼閫夐」
+const taxRateOptions = ref([
+ { name: '0%', value: 0 },
+ { name: '1%', value: 1 },
+ { name: '3%', value: 3 },
+ { name: '6%', value: 6 },
+ { name: '9%', value: 9 },
+ { name: '13%', value: 13 },
+])
+
+// 杩斿洖涓婁竴椤�
+const goBack = () => {
+ uni.removeStorageSync('stockInEditRow')
+ uni.navigateBack()
+}
+
+// 鐗╁搧绫诲瀷閫夋嫨
+const onItemTypeSelect = (item) => {
+ form.value.itemType = item.value
+ showItemTypePicker.value = false
+}
+
+// 绋庣巼閫夋嫨
+const onTaxRateSelect = (item) => {
+ form.value.taxRate = item.value
+ showTaxRatePicker.value = false
+ calculateExclusivePrice()
+}
+
+// 鏃ユ湡閫夋嫨纭
+const onDateConfirm = (e) => {
+ form.value.inboundDate = formatDateToYMD(e.value)
+ showDatePicker.value = false
+}
+
+// 璁$畻鍚◣鎬讳环
+const calculateTotalPrice = () => {
+ const num = parseFloat(form.value.inboundNum) || 0
+ const price = parseFloat(form.value.taxInclusiveUnitPrice) || 0
+ form.value.taxInclusiveTotalPrice = (num * price).toFixed(2)
+ calculateExclusivePrice()
+}
+
+// 璁$畻涓嶅惈绋庢�讳环
+const calculateExclusivePrice = () => {
+ const totalPrice = parseFloat(form.value.taxInclusiveTotalPrice) || 0
+ const taxRate = parseFloat(form.value.taxRate) || 0
+ form.value.taxExclusiveTotalPrice = (totalPrice / (1 + taxRate / 100)).toFixed(2)
+}
+
+// 鎻愪氦琛ㄥ崟
+const submitForm = () => {
+ formRef.value.validate().then(() => {
+ uni.showLoading({
+ title: '淇濆瓨涓�...',
+ mask: true
+ })
+
+ const apiCall = operationType.value === 'add' ? addStockInCustom : updateStockInCustom
+
+ apiCall(form.value).then(() => {
+ uni.hideLoading()
+ uni.showToast({
+ title: '淇濆瓨鎴愬姛',
+ icon: 'success'
+ })
+ setTimeout(() => {
+ goBack()
+ }, 1500)
+ }).catch(() => {
+ uni.hideLoading()
+ uni.showToast({
+ title: '淇濆瓨澶辫触',
+ icon: 'none'
+ })
+ })
+ }).catch(() => {
+ uni.showToast({
+ title: '璇峰~鍐欏畬鏁翠俊鎭�',
+ icon: 'none'
+ })
+ })
+}
+
+onLoad((options) => {
+ if (options.type) {
+ operationType.value = options.type
+ }
+
+ // 缂栬緫妯″紡锛屽姞杞芥暟鎹�
+ if (operationType.value === 'edit') {
+ const storedData = uni.getStorageSync('stockInEditRow')
+ if (storedData) {
+ const row = JSON.parse(storedData)
+ form.value = { ...row }
+ }
+ } else {
+ // 鏂板妯″紡锛岃缃粯璁ゆ棩鏈�
+ form.value.inboundDate = formatDateToYMD(new Date())
+ }
+})
+</script>
+
+<style scoped lang="scss">
+.stock-detail-page {
+ min-height: 100vh;
+ background: #f5f5f5;
+ padding-bottom: 80px;
+}
+
+.form-section {
+ background: #fff;
+ margin-bottom: 12px;
+ padding: 16px;
+}
+
+.section-title {
+ font-size: 16px;
+ font-weight: 600;
+ color: #333;
+ margin-bottom: 16px;
+ padding-left: 12px;
+ border-left: 4px solid #2979ff;
+}
+
+.footer-btns {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ display: flex;
+ gap: 12px;
+ padding: 12px 16px;
+ background: #fff;
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.04);
+ z-index: 999;
+}
+
+.cancel-btn {
+ flex: 1;
+ background: #f5f5f5;
+ color: #666;
+ border: none;
+}
+
+.save-btn {
+ flex: 1;
+ background: #2979ff;
+ color: #fff;
+ border: none;
+}
+</style>
diff --git a/src/pages/inventoryManagement/receiptManagement/index.vue b/src/pages/inventoryManagement/receiptManagement/index.vue
new file mode 100644
index 0000000..257ea3e
--- /dev/null
+++ b/src/pages/inventoryManagement/receiptManagement/index.vue
@@ -0,0 +1,406 @@
+<template>
+ <view class="stock-in-page">
+ <PageHeader title="鑷畾涔夊叆搴�" @back="goBack" />
+
+ <!-- 鎼滅储鍖哄煙 -->
+ <view class="search-section">
+ <view class="search-bar">
+ <view class="search-input">
+ <up-input
+ v-model="searchForm.supplierName"
+ placeholder="璇疯緭鍏ヤ緵搴斿晢鍚嶇О"
+ clearable
+ />
+ </view>
+ <view class="search-button" @click="handleQuery">
+ <up-icon name="search" size="24" color="#999"></up-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>
+
+ <!-- 鍒楄〃 -->
+ <view class="stock-list" v-if="tableData.length > 0">
+ <view v-for="(item, index) in tableData" :key="index" class="stock-item">
+ <view class="item-header">
+ <view class="item-left">
+ <view class="batch-icon">
+ <up-icon name="file-text" size="16" color="#ffffff"></up-icon>
+ </view>
+ <text class="batch-text">{{ item.inboundBatches }}</text>
+ </view>
+ <view class="item-right">
+ <text class="time-text">{{ item.inboundDate }}</text>
+ </view>
+ </view>
+ <up-divider></up-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">{{ item.itemType }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍏ュ簱鏁伴噺</text>
+ <text class="detail-value highlight">{{ item.inboundNum }} {{ item.unit }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍚◣鍗曚环</text>
+ <text class="detail-value">楼{{ item.taxInclusiveUnitPrice }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍚◣鎬讳环</text>
+ <text class="detail-value price">楼{{ item.taxInclusiveTotalPrice }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">绋庣巼</text>
+ <text class="detail-value">{{ item.taxRate }}%</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍏ュ簱浜�</text>
+ <text class="detail-value">{{ item.createBy }}</text>
+ </view>
+ </view>
+
+ <view class="item-actions">
+ <u-button type="primary" size="small" @click="handleEdit(item)">缂栬緫</u-button>
+ <u-button type="error" size="small" plain @click="handleDeleteSingle(item)">鍒犻櫎</u-button>
+ </view>
+ </view>
+ </view>
+
+ <view v-else class="no-data">
+ <text>鏆傛棤鏁版嵁</text>
+ </view>
+
+ <!-- 娴姩鎿嶄綔鎸夐挳 -->
+ <view class="fab-button" @click="handleAdd">
+ <up-icon name="plus" size="24" color="#ffffff"></up-icon>
+ </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>
+
+ <!-- 琛ㄥ崟寮圭獥 -->
+ <form-dia-manual ref="formDiaManual" @close="getList" @success="getList" />
+ </view>
+</template>
+
+<script setup>
+import { ref, reactive, toRefs, onMounted } from 'vue'
+import { onShow } from '@dcloudio/uni-app'
+import dayjs from 'dayjs'
+import PageHeader from '@/components/PageHeader.vue'
+import FormDiaManual from './components/formDiaManual.vue'
+import useUserStore from '@/store/modules/user'
+import { formatDateToYMD } from '@/utils/ruoyi'
+import {
+ getInPageByCustom,
+ delStockInCustom
+} from "@/api/inventoryManagement/stockIn.js"
+
+const userStore = useUserStore()
+
+const tableData = ref([])
+const showDatePicker = ref(false)
+const dateValue = ref(new Date().getTime())
+const formDiaManual = ref(null)
+
+const page = reactive({
+ current: 1,
+ size: 20,
+})
+const total = ref(0)
+
+const data = reactive({
+ searchForm: {
+ supplierName: '',
+ timeStr: '',
+ },
+})
+const { searchForm } = toRefs(data)
+
+// 缁熶竴鐢� dayjs 杈撳嚭 YYYY-MM-DD
+const formatYMDLocal = (ts) => dayjs(Number(ts)).format('YYYY-MM-DD')
+
+// 杩斿洖涓婁竴椤�
+const goBack = () => {
+ uni.navigateBack()
+}
+
+// 鏌ヨ鍒楄〃
+const handleQuery = () => {
+ page.current = 1
+ getList()
+}
+
+const getList = () => {
+ uni.showLoading({
+ title: '鍔犺浇涓�...',
+ mask: true
+ })
+
+ const params = {
+ ...page,
+ supplierName: searchForm.value.supplierName,
+ timeStr: searchForm.value.timeStr
+ }
+
+ getInPageByCustom(params).then(res => {
+ uni.hideLoading()
+ tableData.value = res.data.records || []
+ total.value = res.data.total || 0
+ }).catch(() => {
+ uni.hideLoading()
+ uni.showToast({
+ title: '鍔犺浇澶辫触',
+ icon: 'none'
+ })
+ })
+}
+
+// 鎵撳紑鏃ユ湡閫夋嫨鍣紙绠�鍗曞彲闈狅級
+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 handleAdd = () => {
+ formDiaManual.value?.openDialog('add')
+}
+
+// 缂栬緫
+const handleEdit = (item) => {
+ formDiaManual.value?.openDialog('edit', item)
+}
+
+// 鍒犻櫎鍗曟潯
+const handleDeleteSingle = (item) => {
+ // 妫�鏌ユ槸鍚︽槸鏈汉鍒涘缓
+ if (item.createBy !== userStore.nickName) {
+ uni.showToast({
+ title: '涓嶅彲鍒犻櫎浠栦汉缁存姢鐨勬暟鎹�',
+ icon: 'none'
+ })
+ return
+ }
+
+ uni.showModal({
+ title: '鍒犻櫎',
+ content: '纭鍒犻櫎璇ュ叆搴撹褰曞悧锛�',
+ success: (res) => {
+ if (res.confirm) {
+ delStockInCustom({ ids: [item.id] }).then(() => {
+ uni.showToast({
+ title: '鍒犻櫎鎴愬姛',
+ icon: 'success'
+ })
+ getList()
+ }).catch(() => {
+ uni.showToast({
+ title: '鍒犻櫎澶辫触',
+ icon: 'none'
+ })
+ })
+ }
+ }
+ })
+}
+
+onShow(() => {
+ getList()
+})
+</script>
+
+<style scoped lang="scss">
+.stock-in-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;
+}
+
+.fab-button {
+ position: fixed;
+ right: 20px;
+ bottom: 80px;
+ width: 56px;
+ height: 56px;
+ background: #2979ff;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 4px 12px rgba(41, 121, 255, 0.4);
+ z-index: 999;
+}
+</style>
diff --git a/src/static/images/icon/chuchaiguanli@2x.png b/src/static/images/icon/chuchaiguanli@2x.png
new file mode 100644
index 0000000..ea94f73
--- /dev/null
+++ b/src/static/images/icon/chuchaiguanli@2x.png
Binary files differ
diff --git a/src/static/images/icon/gongchuguanli@2x.png b/src/static/images/icon/gongchuguanli@2x.png
new file mode 100644
index 0000000..a05a03e
--- /dev/null
+++ b/src/static/images/icon/gongchuguanli@2x.png
Binary files differ
diff --git a/src/static/images/icon/qingjiaguanli@2x.png b/src/static/images/icon/qingjiaguanli@2x.png
new file mode 100644
index 0000000..4655a22
--- /dev/null
+++ b/src/static/images/icon/qingjiaguanli@2x.png
Binary files differ
diff --git a/src/static/images/icon/rukuguanli@2x.png b/src/static/images/icon/rukuguanli@2x.png
new file mode 100644
index 0000000..aa278da
--- /dev/null
+++ b/src/static/images/icon/rukuguanli@2x.png
Binary files differ
--
Gitblit v1.9.3