Pārlūkot izejas kodu

feat: 新增资产明细、交易记录、补仓页面

ext.zhangbin71 1 nedēļu atpakaļ
vecāks
revīzija
4de49196f0

+ 33 - 0
api/merchant.js

@@ -20,4 +20,37 @@ export function footprintScan(data) {
  */
 export function footprintList(data) {
   return request.get("merchant/footprint/list",data);
+}
+/**
+ * 商家提交补货申请
+ * @param
+ */
+export function restockSubmitAPI(data) {
+  return request.post("merchant/restock/submit", data);
+}
+
+
+/**
+ * 查询当前登录商户金属资产明细
+ * @param
+ */
+export function fetchMerchantMetalBalanceAPI(data) {
+  return request.get("merchantgoldprincipal/statistics");
+}
+
+
+/**
+ * 根据金属类型和增减类型查询流水记录
+ * @param
+ */
+export function fetchMerchantRecordAPI(params) {
+  return request.get(`merchantgoldprincipal/records?metalType=${params.metalType}&limit=${params.limit}&page=${params.page}&type=${params.type}`);
+}
+
+/**
+ * 查询当前商家的补货申请列表
+ * @param
+ */
+export function fetchMerchantRestockListAPI(params) {
+  return request.get(`merchant/restock/list?metalType=${params.metalType}&limit=${params.limit}&page=${params.page}&type=${params.type}`);
 }

+ 1 - 0
config/app.js

@@ -1,6 +1,7 @@
 // let domain = "https://www.shuibeibyg.com/front-api"; // 正式环境IP
 // let domain = "https://test.shuibeibyg.com/front-api"; // 测试环境IP
 let domain = 'http://192.168.100.199:8081' // 晋守桦IP
+// let domain = 'http://192.168.100.246:8081' // 韩朝龙IP
 let share = "https://www.shuibeibyg.com";
 
 // export const H5_BASE_URL = "http://192.168.3.10:5174"; // 本地测试

+ 24 - 0
pages.json

@@ -319,6 +319,30 @@
 						"navigationBarBackgroundColor": "#fff",
 						"navigationBarTextStyle": "black"
 					}
+				},
+				{
+					"path": "user_asset/stock_in/stock_in",
+					"style": {
+						"navigationBarTitleText": "补仓",
+						"navigationBarBackgroundColor": "#fff",
+						"navigationBarTextStyle": "black"
+					}
+				},
+				{
+					"path": "user_asset/asset_info/asset_info",
+					"style": {
+						"navigationBarTitleText": "资产明细",
+						"navigationBarBackgroundColor": "#fff",
+						"navigationBarTextStyle": "black"
+					}
+				},
+				{
+					"path": "user_asset/record_list/record_list",
+					"style": {
+						"navigationBarTitleText": "交易明细",
+						"navigationBarBackgroundColor": "#fff",
+						"navigationBarTextStyle": "black"
+					}
 				}
 			]
 		}

+ 3 - 1
pages/index/index.vue

@@ -16,7 +16,8 @@
       </template>
       <template #right></template>
     </up-navbar>
-    <view class="page-index" :class="{ bgf: navIndex > 0 }">
+    <!-- <view class="page-index" :class="{ bgf: navIndex > 0 }"> -->
+    <view class="page-index">
       <view class="top-box">
         <view class="header">
           <view class="serch-wrapper">
@@ -244,6 +245,7 @@ onShow(() => {
 });
 onLoad(async (options)=>{
   merchantId.value = uni.getStorageSync('merchantId') || '';
+  console.log("merchantId===>",merchantId.value)
   uni.removeStorageSync('merchantId');
   if(merchantId.value != ''){
     getSbmerchantInfoFn();

+ 2 - 1
pages/user/index.vue

@@ -361,7 +361,8 @@ const group1 = ref([
     is_show: false,
     width: 37,
     height: 70,
-    url: "/pages/users/vault/index",
+    // url: "/pages/users/vault/index",
+    url: "/pages/users/user_asset/asset_info/asset_info",
   },
 ]);
 

+ 487 - 0
pages/users/user_asset/asset_info/asset_info.vue

@@ -0,0 +1,487 @@
+<template>
+	<view class="asset_container">
+		<view class="asset_refresh_box">
+			<view class="refresh_time">
+				更新于:{{refreshTime}}
+			</view>
+			<view class="refresh_btn" @click="refreshClickHandle">
+				<image src="/static/images/refresh_icon.png" mode="heightFix" class="refresh_icon"></image>
+				<text>刷新</text>
+			</view>
+		</view>
+
+		<scroll-view class="asset_list" scroll-y="true">
+			<view class="list_container">
+				<view class="asset_item">
+					<view class="asset_title">
+						<image src="/static/images/au_icon.png" mode="widthFix" class="title_icon"></image>
+						<view class="">
+							黄金资产
+						</view>
+					</view>
+					<view class="asset_count">
+						<view class="total_count">
+							<view class="count_title">
+								累计进货
+							</view>
+							<view class="count_num">
+								{{auStock.total || 0}}g
+							</view>
+						</view>
+						<view class="total_count">
+							<view class="count_title">
+								可用库存
+							</view>
+							<view class="count_num" :class="{green: Number(auStock.useful)<0}">
+								{{auStock.useful || 0}}g
+							</view>
+						</view>
+						<view class="total_count">
+							<view class="count_title">
+								累计销售
+							</view>
+							<view class="count_num">
+								{{auStock.used || 0}}g
+							</view>
+						</view>
+					</view>
+					<view class="asset_tips" v-if="Number(auStock.useful)<0">
+						<image src="/static/images/warn_icon.png" mode="heightFix" class="warn_icon"></image>
+						<text>库存过低,请及时补货</text>
+					</view>
+					<view class="asset_btns">
+						<view class="record_list" @click="recordClickHandle(1)">
+							交易记录
+						</view>
+						<view class="stock_in" @click="stockInClickHandle(1)">
+							补仓
+						</view>
+					</view>
+				</view>
+
+				<view class="asset_item">
+					<view class="asset_title">
+						<image src="/static/images/pt_icon.png" mode="widthFix" class="title_icon"></image>
+						<view class="">
+							铂金资产
+						</view>
+					</view>
+					<view class="asset_count">
+						<view class="total_count">
+							<view class="count_title">
+								累计进货
+							</view>
+							<view class="count_num">
+								{{ptStock.total || 0}}g
+							</view>
+						</view>
+						<view class="total_count">
+							<view class="count_title">
+								可用库存
+							</view>
+							<view class="count_num" :class="{green: Number(ptStock.useful)<0}">
+								{{ptStock.useful || 0}}g
+							</view>
+						</view>
+						<view class="total_count">
+							<view class="count_title">
+								累计销售
+							</view>
+							<view class="count_num">
+								{{ptStock.used || 0}}g
+							</view>
+						</view>
+					</view>
+					<view class="asset_tips" v-if="Number(ptStock.useful)<0">
+						<image src="/static/images/warn_icon.png" mode="heightFix" class="warn_icon"></image>
+						<text>库存过低,请及时补货</text>
+					</view>
+					<view class="asset_btns">
+						<view class="record_list" @click="recordClickHandle(2)">
+							交易记录
+						</view>
+						<view class="stock_in" @click="stockInClickHandle(2)">
+							补仓
+						</view>
+					</view>
+				</view>
+
+				<view class="asset_item">
+					<view class="asset_title">
+						<image src="/static/images/ag_icon.png" mode="widthFix" class="title_icon"></image>
+						<view class="">
+							白银资产
+						</view>
+					</view>
+					<view class="asset_count">
+						<view class="total_count">
+							<view class="count_title">
+								累计进货
+							</view>
+							<view class="count_num">
+								{{agStock.total || 0}}g
+							</view>
+						</view>
+						<view class="total_count">
+							<view class="count_title">
+								可用库存
+							</view>
+							<view class="count_num" :class="{green: Number(agStock.useful)<0}">
+								{{agStock.useful || 0}}g
+							</view>
+						</view>
+						<view class="total_count">
+							<view class="count_title">
+								累计销售
+							</view>
+							<view class="count_num">
+								{{agStock.used || 0}}g
+							</view>
+						</view>
+					</view>
+					<view class="asset_tips" v-if="Number(agStock.useful)<0">
+						<image src="/static/images/warn_icon.png" mode="heightFix" class="warn_icon"></image>
+						<text>库存过低,请及时补货</text>
+					</view>
+					<view class="asset_btns">
+						<view class="record_list" @click="recordClickHandle(3)">
+							交易记录
+						</view>
+						<view class="stock_in" @click="stockInClickHandle(3)">
+							补仓
+						</view>
+					</view>
+				</view>
+			</view>
+
+		</scroll-view>
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref,
+	} from 'vue';
+	import {
+		onLoad,
+		onShow,
+		onReachBottom
+	} from "@dcloudio/uni-app";
+
+	import {
+		restockSubmitAPI,
+		fetchMerchantMetalBalanceAPI
+	} from '@/api/merchant';
+
+	import {
+		useImageUpload
+	} from "@/hooks/useImageUpload";
+	import {
+		useToast
+	} from "@/hooks/useToast";
+
+	import {
+		throttle
+	} from '@/uni_modules/uview-plus';
+
+
+	onLoad(() => {
+		console.log("asset_list page =====>  Loaded")
+		
+	})
+	
+		
+	onShow(()=>{
+		fetchBalance()
+	})
+
+	const auStock = ref({
+		total: '-',
+		useful: '-',
+		used: '-',
+	})
+	const ptStock = ref({
+		total: '-',
+		useful: '-',
+		used: '-',
+	})
+	const agStock = ref({
+		total: '-',
+		useful: '-',
+		used: '-',
+	})
+
+	const refreshTime = ref()
+
+
+	/**
+	 * 获取当前登录商户金属资产明细
+	 */
+	function fetchBalance(isRefresh) {
+		fetchMerchantMetalBalanceAPI().then(res => {
+			console.log(res)
+			const {
+				data,
+				code
+			} = res
+			console.log(data, code)
+			if (isRefresh) {
+				uni.showToast({
+					title: '刷新成功',
+					icon: 'none',
+					duration: 1000
+				})
+			}
+
+			if (code === 200 && data.length > 0) {
+				refreshTime.value = fetchCurrentTime()
+
+				data.forEach(item => {
+					console.log(item);
+					switch (item.metalType) {
+						case 1:
+							auStock.value = {
+								total: item.totalIncreaseWeight,
+								useful: item.availableStock,
+								used: item.totalDecreaseWeight
+							}
+							break;
+						case 2:
+							ptStock.value = {
+								total: item.totalIncreaseWeight,
+								useful: item.availableStock,
+								used: item.totalDecreaseWeight
+							}
+							break;
+						case 3:
+							agStock.value = {
+								total: item.totalIncreaseWeight,
+								useful: item.availableStock,
+								used: item.totalDecreaseWeight
+							}
+							break;
+						default:
+							break;
+					}
+				})
+			}
+		}).catch(err => {
+			console.log(err);
+		})
+	}
+
+	function fetchCurrentTime() {
+		const now = new Date();
+		let year = now.getFullYear(),
+			month = now.getMonth() + 1,
+			day = now.getDate(),
+			hour = now.getHours(),
+			min = now.getMinutes(),
+			sec = now.getSeconds();
+
+		month = month < 10 ? ('0' + month) : (month)
+		day = day < 10 ? ('0' + day) : (day)
+		hour = hour < 10 ? ('0' + hour) : (hour)
+		min = min < 10 ? ('0' + min) : (min)
+		sec = sec < 10 ? ('0' + sec) : (sec)
+
+		return `${year}-${month}-${day} ${hour}:${min}:${sec}`
+	}
+
+	function recordClickHandle(type) {
+		uni.navigateTo({
+			url: `/pages/users/user_asset/record_list/record_list?type=${type}`
+		})
+	}
+
+	function stockInClickHandle(type) {
+		uni.navigateTo({
+			url: `/pages/users/user_asset/stock_in/stock_in?type=${type}`
+		})
+	}
+
+	function refreshClickHandle() {
+		throttle(() => {
+			fetchBalance(1)
+		}, 1000)
+	}
+</script>
+
+<style scoped lang="scss">
+	uni-page-body {
+		height: 100%;
+	}
+
+	.asset_refresh_box {
+		width: 750rpx;
+		display: flex;
+		justify-content: space-between;
+		padding: 0 0 0 32rpx;
+		height: 76rpx;
+		align-items: center;
+		// position: absolute;
+		// top:0;
+		// left: 0;
+
+		background-color: #FEF8E6;
+
+		.refresh_time {
+			font-size: 28rpx;
+			color: #333;
+		}
+
+		.refresh_btn {
+			display: flex;
+			align-items: center;
+			padding: 20rpx 32rpx 20rpx 20rpx;
+			font-size: 24rpx;
+			line-height: 32rpx;
+			color: #F8C008;
+
+			.refresh_icon {
+				// width: 32rpx;
+				height: 32rpx;
+				margin-right: 8rpx;
+			}
+		}
+	}
+
+	.asset_container {
+		// padding-top: 92rpx;
+		background-color: #F9F7F0;
+		height: 100%;
+		display: flex;
+		flex-direction: column;
+		justify-content: flex-start;
+		align-items: center;
+
+		.asset_list {
+			width: 100%;
+			background-color: #F9F7F0;
+			height: 400rpx;
+			flex: 1;
+			padding: 16rpx;
+
+			.list_container {
+				padding-bottom: 20rpx;
+			}
+
+			.asset_item {
+				width: 100%;
+				border-radius: 16rpx;
+				background-color: #fff;
+				min-height: 200rpx;
+				padding: 20rpx;
+				margin-bottom: 20rpx;
+
+				.asset_title {
+					width: 100%;
+					display: flex;
+					justify-content: flex-start;
+					align-items: center;
+					font-size: 32rpx;
+					color: #333;
+					font-weight: bold;
+
+					.title_icon {
+						width: 48rpx;
+						height: 48rpx;
+						margin-right: 8rpx;
+					}
+				}
+
+				.asset_count {
+					width: 100%;
+					padding: 16rpx;
+					border-radius: 16rpx;
+					background-color: #F9F7F0;
+					display: flex;
+					justify-content: space-between;
+					align-items: center;
+					margin-top: 20rpx;
+
+					.total_count {
+						display: flex;
+						flex: 1;
+						flex-direction: column;
+						align-items: center;
+						justify-content: center;
+						min-width: 160rpx;
+						flex-shrink: 0;
+
+						.count_title {
+							font-size: 24rpx;
+							color: #333;
+							margin-bottom: 10rpx;
+						}
+
+						.count_num {
+							font-size: 40rpx;
+							color: #3D3D3D;
+							font-weight: bold;
+							max-width: 200rpx;
+							overflow: hidden;
+							text-overflow: ellipsis;
+							white-space: nowrap;
+
+							&.green {
+								color: #2DAB6C;
+							}
+						}
+					}
+				}
+
+				.asset_tips {
+					width: 100%;
+					height: 80rpx;
+					display: flex;
+					justify-content: flex-start;
+					align-items: center;
+					background-color: #FEEAEA;
+					border-radius: 16rpx;
+					padding: 18rpx;
+					font-size: 28rpx;
+					line-height: 32rpx;
+					color: #F52929;
+					margin: 20rpx 0;
+
+					.warn_icon {
+						// width: 32rpx;
+						height: 32rpx;
+						margin-right: 16rpx;
+					}
+				}
+
+				.asset_btns {
+					width: 100%;
+					display: flex;
+					justify-content: space-between;
+					margin-top: 20rpx;
+
+					.record_list {
+						width: 330rpx;
+						height: 60rpx;
+						line-height: 60rpx;
+						text-align: center;
+						color: #333;
+						font-size: 28rpx;
+						border-radius: 18rpx;
+						background-color: rgba(248, 192, 8, 0.10);
+					}
+
+					.stock_in {
+						width: 330rpx;
+						height: 60rpx;
+						line-height: 60rpx;
+						text-align: center;
+						color: #333;
+						font-size: 28rpx;
+						border-radius: 18rpx;
+						background-color: #F8C008;
+
+					}
+				}
+			}
+		}
+	}
+</style>

+ 807 - 0
pages/users/user_asset/record_list/record_list.vue

@@ -0,0 +1,807 @@
+<template>
+	<view class="asset_container">
+		<view class="asset_refresh_box">
+			<view class="refresh_time">
+				更新于:{{refreshTime}}
+			</view>
+			<view class="refresh_btn" @click="refreshClickHandle">
+				<image src="/static/images/refresh_icon.png" mode="heightFix" class="refresh_icon"></image>
+				<text>刷新</text>
+			</view>
+		</view>
+		<view class="asset_info">
+			<view class="asset_item" v-if="metalType==1">
+				<view class="asset_title">
+					<image src="/static/images/au_icon.png" mode="widthFix" class="title_icon"></image>
+					<view class="">
+						黄金资产
+					</view>
+				</view>
+				<view class="asset_count">
+					<view class="total_count">
+						<view class="count_title">
+							累计进货
+						</view>
+						<view class="count_num">
+							{{auStock.total || 0}}g
+						</view>
+					</view>
+					<view class="total_count">
+						<view class="count_title">
+							可用库存
+						</view>
+						<view class="count_num" :class="{green: Number(auStock.useful)<0}">
+							{{auStock.useful || 0}}g
+						</view>
+					</view>
+					<view class="total_count">
+						<view class="count_title">
+							累计销售
+						</view>
+						<view class="count_num">
+							{{auStock.used || 0}}g
+						</view>
+					</view>
+				</view>
+			</view>
+
+			<view class="asset_item" v-if="metalType==2">
+				<view class="asset_title">
+					<image src="/static/images/pt_icon.png" mode="widthFix" class="title_icon"></image>
+					<view class="">
+						铂金资产
+					</view>
+				</view>
+				<view class="asset_count">
+					<view class="total_count">
+						<view class="count_title">
+							累计进货
+						</view>
+						<view class="count_num">
+							{{ptStock.total || 0}}g
+						</view>
+					</view>
+					<view class="total_count">
+						<view class="count_title">
+							可用库存
+						</view>
+						<view class="count_num" :class="{green: Number(ptStock.useful)<0}">
+							{{ptStock.useful || 0}}g
+						</view>
+					</view>
+					<view class="total_count">
+						<view class="count_title">
+							累计销售
+						</view>
+						<view class="count_num">
+							{{ptStock.used || 0}}g
+						</view>
+					</view>
+				</view>
+			</view>
+
+			<view class="asset_item" v-if="metalType==3">
+				<view class="asset_title">
+					<image src="/static/images/ag_icon.png" mode="widthFix" class="title_icon"></image>
+					<view class="">
+						白银资产
+					</view>
+				</view>
+				<view class="asset_count">
+					<view class="total_count">
+						<view class="count_title">
+							累计进货
+						</view>
+						<view class="count_num">
+							{{agStock.total || 0}}g
+						</view>
+					</view>
+					<view class="total_count">
+						<view class="count_title">
+							可用库存
+						</view>
+						<view class="count_num" :class="{green: Number(agStock.useful)<0}">
+							{{agStock.useful || 0}}g
+						</view>
+					</view>
+					<view class="total_count">
+						<view class="count_title">
+							累计销售
+						</view>
+						<view class="count_num">
+							{{agStock.used || 0}}g
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+
+		<view class="menu">
+			<view class="menu_btn" :class="{active: menuType==1}" @click="toggleMenu(1)">
+				<view class="menu_title">
+					交易记录
+				</view>
+				<view class="menu_bar">
+
+				</view>
+			</view>
+			<view class="menu_btn btn_rt" :class="{active: menuType==2}" @click="toggleMenu(2)">
+				<view class="menu_title">
+					入库审核
+				</view>
+				<view class="menu_bar">
+
+				</view>
+			</view>
+		</view>
+		<view class="list_filter" v-show="menuType==1">
+			<view class="filter_title">
+
+			</view>
+			<picker @change="bindPickerChange" :value="cValue" :range="filterRange">
+				<view class="filter_btn">
+					<image src="/static/images/filter_icon.png" mode="heightFix" class="filter_icon"></image>
+					<text>筛选</text>
+				</view>
+			</picker>
+			<!-- <view class="filter_btn" @click="refreshClickHandle">
+				<image src="/static/images/filter_icon.png" mode="heightFix" class="filter_icon"></image>
+				<text>筛选</text>
+			</view> -->
+		</view>
+		<scroll-view class="asset_list" scroll-y="true" v-show="menuType==1" :lower-threshold='100'
+			:scroll-top='recordScrollTop' @scrolltolower="nextPageRecord" @scroll="scrollRecord">
+			<view class="list_container">
+				<view class="record_card" v-for="(item,index) in recordList" :key="item.id">
+					<view class="record_left">
+						<view class="record_title">
+							<view class="record_name">
+								{{item.metalTypeName}}-{{item.typeName}}
+							</view>
+						</view>
+						<view class="record_time">
+							{{item.createTime}}
+						</view>
+					</view>
+					<view class="record_right" :class="{green: item.type==0}">
+						{{item.type==0?'-':'+'}}{{item.weight}}g
+					</view>
+				</view>
+			</view>
+
+		</scroll-view>
+		<scroll-view class="asset_list" scroll-y="true" v-show="menuType==2" :lower-threshold='100'
+			:scroll-top='approveScrollTop' @scrolltolower="nextPageApprove" @scroll="scrollApprove">
+			<view class="list_container">
+				<view class="record_card" v-for="(item,index) in approveList" :key="item.id">
+					<view class="record_left">
+						<view class="record_title">
+							<view class="record_name">
+								{{item.metalType==1?'黄金':item.metalType==2?'铂金':item.metalType==3?'白银':'其他'}}-入库
+							</view>
+							<view class="record_status"
+								:class="item.auditStatus==2?'danger':item.auditStatus==0?'warn':'success'">
+								{{item.auditStatus==2?'审核拒绝':item.auditStatus==0?'审核中':'审核通过'}}
+							</view>
+						</view>
+						<view class="record_time">
+							{{item.createTime}}
+						</view>
+					</view>
+					<view class="record_right">
+						+{{item.restockWeight}}g
+					</view>
+				</view>
+			</view>
+
+		</scroll-view>
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref,
+	} from 'vue';
+	import {
+		onLoad,
+		onShow,
+		onReachBottom
+	} from "@dcloudio/uni-app";
+
+	import {
+		restockSubmitAPI,
+		fetchMerchantMetalBalanceAPI,
+		fetchMerchantRecordAPI,
+		fetchMerchantRestockListAPI
+	} from '@/api/merchant';
+
+	import {
+		useImageUpload
+	} from "@/hooks/useImageUpload";
+	import {
+		useToast
+	} from "@/hooks/useToast";
+
+	import {
+		throttle
+	} from '@/uni_modules/uview-plus';
+
+
+	onLoad((params) => {
+		metalType.value = params.type
+		console.log("asset_list page =====>  Loaded")
+		fetchBalance();
+		fetchRecordList();
+		fetchApproveList();
+	})
+
+	const auStock = ref({
+		total: '-',
+		useful: '-',
+		used: '-',
+	})
+	const ptStock = ref({
+		total: '-',
+		useful: '-',
+		used: '-',
+	})
+	const agStock = ref({
+		total: '-',
+		useful: '-',
+		used: '-',
+	})
+	const cValue = ref(3)
+	const filterRange = ref(['出库', '入库', '全部'])
+
+	const refreshTime = ref()
+
+	const metalType = ref(1)
+
+	const menuType = ref(1)
+
+	const recordScrollTop = ref(0)
+	const approveScrollTop = ref(0)
+
+	const recordParams = ref({
+		page: 1,
+		limit: 10,
+		hasMore: true,
+		type: ''
+	})
+
+	const approveParams = ref({
+		page: 1,
+		limit: 10,
+		hasMore: true,
+	})
+
+	const recordList = ref([]);
+
+	const approveList = ref([])
+	
+	function scrollRecord(e){
+		console.log(e.detail.scrollTop,recordScrollTop)
+	}
+	
+	function scrollApprove(e){
+		console.log(e.detail.scrollTop,approveScrollTop)
+	}
+
+
+	/**
+	 * 获取当前登录商户金属资产明细
+	 */
+	function fetchBalance(isRefresh) {
+		fetchMerchantMetalBalanceAPI().then(res => {
+			console.log(res)
+			const {
+				data,
+				code
+			} = res
+			console.log(data, code)
+			if (isRefresh) {
+				uni.showToast({
+					title: '刷新成功',
+					icon: 'none',
+					duration: 1000
+				})
+			}
+
+			if (code === 200 && data.length > 0) {
+				refreshTime.value = fetchCurrentTime()
+
+				data.forEach(item => {
+					console.log(item);
+					switch (item.metalType) {
+						case 1:
+							auStock.value = {
+								total: item.totalIncreaseWeight,
+								useful: item.availableStock,
+								used: item.totalDecreaseWeight
+							}
+							break;
+						case 2:
+							ptStock.value = {
+								total: item.totalIncreaseWeight,
+								useful: item.availableStock,
+								used: item.totalDecreaseWeight
+							}
+							break;
+						case 3:
+							agStock.value = {
+								total: item.totalIncreaseWeight,
+								useful: item.availableStock,
+								used: item.totalDecreaseWeight
+							}
+							break;
+						default:
+							break;
+					}
+				})
+			}
+		}).catch(err => {
+			console.log(err);
+		})
+	}
+
+	function nextPageRecord() {
+		console.log("到底了")
+		if (!recordParams.value.hasMore) {
+			return uni.showToast({
+				title: "没有更多了",
+				icon: "none",
+				duration: 1000
+			})
+		}
+		recordParams.value.page += 1;
+		fetchRecordList()
+
+	}
+
+	function nextPageApprove() {
+		// console.log("到底了")
+		if (!approveParams.value.hasMore) {
+			return uni.showToast({
+				title: "没有更多了",
+				icon: "none",
+				duration: 1000
+			})
+		}
+		approveParams.value.page += 1;
+		fetchApproveList()
+
+	}
+
+	function bindPickerChange(e) {
+		console.log('picker发送选择改变,携带值为', e.detail.value)
+		recordParams.value = {
+			type: e.detail.value == 2 ? '' : e.detail.value,
+			page: 1,
+			limit: 10,
+			hasMore: true
+		}
+		fetchRecordList()
+	}
+
+	function fetchRecordList() {
+		uni.showLoading({
+			title: "加载中"
+		})
+		fetchMerchantRecordAPI({
+			...recordParams.value,
+			metalType: metalType.value
+		}).then(res => {
+			console.log(res);
+			uni.hideLoading()
+			if (recordParams.value.page == 1) {
+				recordList.value = res?.data?.list || [];
+				recordScrollTop.value = 0
+			} else {
+				recordList.value = recordList.value.concat(res?.data?.list || []);
+			}
+			recordParams.value.hasMore = res?.data?.totalPage > recordParams.value.page
+		}).catch(err => {
+			console.log(err)
+			try {
+				uni.hideLoading()
+			} catch (error) {
+				//TODO handle the exception
+			}
+		})
+	}
+
+	function fetchApproveList() {
+		uni.showLoading({
+			title: "加载中"
+		})
+		fetchMerchantRestockListAPI({
+			...approveParams.value,
+			metalType: metalType.value
+		}).then(res => {
+			console.log(res);
+			uni.hideLoading()
+			if (approveParams.value.page == 1) {
+				approveList.value = res?.data?.list || [];
+				approveScrollTop.value = 0
+			} else {
+				approveList.value = approveList.value.concat(res?.data?.list || []);
+			}
+			approveParams.value.hasMore = res?.data?.hasNextPage
+		}).catch(err => {
+			console.log(err)
+			try {
+				uni.hideLoading()
+			} catch (error) {
+				//TODO handle the exception
+			}
+		})
+	}
+
+	function toggleMenu(type) {
+		menuType.value = type
+	}
+
+	function fetchCurrentTime() {
+		const now = new Date();
+		let year = now.getFullYear(),
+			month = now.getMonth() + 1,
+			day = now.getDate(),
+			hour = now.getHours(),
+			min = now.getMinutes(),
+			sec = now.getSeconds();
+
+		month = month < 10 ? ('0' + month) : (month)
+		day = day < 10 ? ('0' + day) : (day)
+		hour = hour < 10 ? ('0' + hour) : (hour)
+		min = min < 10 ? ('0' + min) : (min)
+		sec = sec < 10 ? ('0' + sec) : (sec)
+
+		return `${year}-${month}-${day} ${hour}:${min}:${sec}`
+	}
+
+	function recordClickHandle(type) {
+		uni.navigateTo({
+			url: `/pages/users/user_asset/record_list/record_list?type=${type}`
+		})
+	}
+
+	function stockInClickHandle(type) {
+		uni.navigateTo({
+			url: `/pages/users/user_asset/stock_in/stock_in?type=${type}`
+		})
+	}
+
+	function refreshClickHandle() {
+		throttle(() => {
+			fetchBalance(1);
+			recordParams.value.page = 1
+			recordParams.value.hasMore = true
+			approveParams.value.page = 1
+			approveParams.value.hasMore = 1
+			fetchRecordList()
+			fetchApproveList()
+		}, 1000)
+	}
+</script>
+
+<style scoped lang="scss">
+	uni-page-body {
+		height: 100%;
+	}
+
+	.asset_refresh_box {
+		width: 750rpx;
+		display: flex;
+		justify-content: space-between;
+		padding: 0 0 0 32rpx;
+		height: 76rpx;
+		align-items: center;
+		// position: absolute;
+		// top:0;
+		// left: 0;
+
+		background-color: #FEF8E6;
+
+		.refresh_time {
+			font-size: 28rpx;
+			color: #333;
+		}
+
+		.refresh_btn {
+			display: flex;
+			align-items: center;
+			padding: 20rpx 32rpx 20rpx 20rpx;
+			font-size: 24rpx;
+			line-height: 32rpx;
+			color: #F8C008;
+
+			.refresh_icon {
+				// width: 32rpx;
+				height: 32rpx;
+				margin-right: 8rpx;
+			}
+		}
+	}
+
+	.asset_container {
+		// padding-top: 92rpx;
+		background-color: #F9F7F0;
+		height: 100%;
+		display: flex;
+		flex-direction: column;
+		justify-content: flex-start;
+		align-items: center;
+
+		.asset_info {
+			width: 100%;
+			padding: 16rpx 16rpx 0;
+		}
+
+		.list_filter {
+			width: 100%;
+			padding: 16rpx 16rpx 0;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+
+			.filter_title {
+				font-size: 32rpx;
+				color: #333;
+				font-weight: bold;
+			}
+
+			.filter_btn {
+				display: flex;
+				align-items: center;
+				padding: 10rpx 32rpx 10rpx 20rpx;
+				font-size: 24rpx;
+				line-height: 32rpx;
+				color: #F8C008;
+
+				.filter_icon {
+					// width: 32rpx;
+					height: 32rpx;
+					margin-right: 8rpx;
+				}
+			}
+		}
+
+		.asset_item {
+			width: 100%;
+			border-radius: 16rpx;
+			background-color: #fff;
+			min-height: 200rpx;
+			padding: 20rpx;
+
+			.asset_title {
+				width: 100%;
+				display: flex;
+				justify-content: flex-start;
+				align-items: center;
+				font-size: 32rpx;
+				color: #333;
+				font-weight: bold;
+
+				.title_icon {
+					width: 48rpx;
+					height: 48rpx;
+					margin-right: 8rpx;
+				}
+			}
+
+			.asset_count {
+				width: 100%;
+				padding: 16rpx;
+				border-radius: 16rpx;
+				background-color: #F9F7F0;
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+				margin-top: 20rpx;
+
+				.total_count {
+					display: flex;
+					flex: 1;
+					flex-direction: column;
+					align-items: center;
+					justify-content: center;
+					min-width: 160rpx;
+					flex-shrink: 0;
+
+					.count_title {
+						font-size: 24rpx;
+						color: #333;
+						margin-bottom: 10rpx;
+					}
+
+					.count_num {
+						font-size: 40rpx;
+						color: #3D3D3D;
+						font-weight: bold;
+						max-width: 200rpx;
+						overflow: hidden;
+						text-overflow: ellipsis;
+						white-space: nowrap;
+
+						&.green {
+							color: #2DAB6C;
+						}
+					}
+				}
+			}
+
+			.asset_tips {
+				width: 100%;
+				height: 80rpx;
+				display: flex;
+				justify-content: flex-start;
+				align-items: center;
+				background-color: #FEEAEA;
+				border-radius: 16rpx;
+				padding: 18rpx;
+				font-size: 28rpx;
+				line-height: 32rpx;
+				color: #F52929;
+				margin: 20rpx 0;
+
+				.warn_icon {
+					// width: 32rpx;
+					height: 32rpx;
+					margin-right: 16rpx;
+				}
+			}
+
+			.asset_btns {
+				width: 100%;
+				display: flex;
+				justify-content: space-between;
+				margin-top: 20rpx;
+
+				.record_list {
+					width: 330rpx;
+					height: 60rpx;
+					line-height: 60rpx;
+					text-align: center;
+					color: #333;
+					font-size: 28rpx;
+					border-radius: 18rpx;
+					background-color: rgba(248, 192, 8, 0.10);
+				}
+
+				.stock_in {
+					width: 330rpx;
+					height: 60rpx;
+					line-height: 60rpx;
+					text-align: center;
+					color: #333;
+					font-size: 28rpx;
+					border-radius: 18rpx;
+					background-color: #F8C008;
+
+				}
+			}
+		}
+
+		.asset_list {
+			width: 100%;
+			background-color: #F9F7F0;
+			height: 400rpx;
+			flex: 1;
+			padding: 16rpx 16rpx 16rpx;
+
+			.list_container {
+				padding-bottom: 20rpx;
+			}
+
+
+		}
+	}
+
+
+	.record_card {
+		width: 100%;
+		display: flex;
+		justify-content: space-between;
+		padding: 20rpx;
+		background-color: #fff;
+		border-radius: 16rpx;
+		margin-bottom: 16rpx;
+
+		.record_left {
+
+			.record_title {
+				display: flex;
+				justify-content: flex-start;
+				align-items: center;
+				margin-bottom: 20rpx;
+
+				.record_name {
+					font-size: 28rpx;
+					color: #333;
+					margin-right: 16rpx;
+				}
+
+				.record_status {
+					height: 40rpx;
+					line-height: 40rpx;
+					padding: 0 16rpx;
+					font-size: 24rpx;
+					border-radius: 8rpx;
+
+					&.success {
+						background-color: #EAF9F0;
+						color: #2DAB6C;
+					}
+
+					&.warn {
+						background-color: #FFF7EC;
+						color: #FDB03C;
+					}
+
+					&.danger {
+						background-color: #FEEAEA;
+						color: #F52929;
+					}
+				}
+			}
+
+			.record_time {
+				font-size: 24rpx;
+				color: #333;
+			}
+		}
+
+		.record_right {
+			font-size: 32rpx;
+			color: #F52929;
+			display: flex;
+			align-items: center;
+
+			&.green {
+				color: #2DAB6C;
+			}
+		}
+	}
+
+	.menu {
+		width: 100%;
+		height: 88rpx;
+		display: flex;
+		margin-top: 20rpx;
+
+		.menu_btn {
+			width: 50%;
+			background-color: #fff;
+			border-radius: 32rpx 0 0 0;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+
+
+			.menu_title {
+				font-size: 28rpx;
+				color: #333;
+			}
+
+			&.active {
+				.menu_title {
+					color: #F8C008;
+					font-weight: bold;
+				}
+
+				.menu_bar {
+					width: 48rpx;
+					height: 4rpx;
+					background-color: #F8C008;
+					border-radius: 0;
+					margin-top: 10rpx;
+				}
+			}
+
+			&.btn_rt {
+				border-radius: 0 32rpx 0 0;
+			}
+		}
+	}
+</style>

+ 489 - 0
pages/users/user_asset/stock_in/stock_in.vue

@@ -0,0 +1,489 @@
+<template>
+	<view class="stock_conatiner">
+		<view class="stock_select_container">
+			<view class="stock_title">
+				<text>选择材质</text>
+			</view>
+			<view class="stock_list">
+				<view class="stock_item" :class="{active: currentStockType==1}" @click="currentStockType=1">
+					<image class="stock_icon" src="/static/images/au_icon.png" mode="widthFix"></image>
+					<text class="stock_name">黄金</text>
+					<text class="stock_num_title">可用库存 </text>
+					<text class="stock_num">{{auStock.useful}}g</text>
+				</view>
+				<view class="stock_item stock_middle" :class="{active: currentStockType==2}"
+					@click="currentStockType=2">
+					<image class="stock_icon" src="/static/images/pt_icon.png" mode="widthFix"></image>
+					<text class="stock_name">铂金</text>
+					<text class="stock_num_title">可用库存 </text>
+					<text class="stock_num">{{ptStock.useful}}g</text>
+				</view>
+				<view class="stock_item" :class="{active: currentStockType==3}" @click="currentStockType=3">
+					<image class="stock_icon" src="/static/images/ag_icon.png" mode="widthFix"></image>
+					<text class="stock_name">白银</text>
+					<text class="stock_num_title">可用库存 </text>
+					<text class="stock_num">{{agStock.useful}}g</text>
+				</view>
+			</view>
+		</view>
+		<view class="stock_ipt_container">
+			<view class="stock_ipt_title">
+				<text>补货数量</text>
+			</view>
+			<input class="stock_ipt" type="digit" v-model="restockWeight" placeholder="请输入补货数量"
+				@input="onInputChange" />
+		</view>
+
+		<view class="stock_img_upload">
+			<view class="stock_img_title">
+				<text>上传进货凭证</text>
+			</view>
+			<view class="upload-img">
+				<view class="upload-box-contanier">
+					<up-upload :fileList="imageList" uploadIcon="plus" @afterRead="afterRead" @delete="deletePic"
+						name="1" multiple :maxCount="1">
+						<template #trigger>
+							<view class="upload-block">
+								<uni-icons size="30" color="#ccc" type="plusempty"></uni-icons>
+							</view>
+						</template>
+					</up-upload>
+				</view>
+			</view>
+			<view class="stock_img_tips">
+				<text>支持 JPG、PNG 等常用图片格式,最多可上传 1 张图片,大小不超过 10MB。</text>
+			</view>
+		</view>
+
+		<view class="stock_bottom_btn">
+			<view class="stock_btn" @click="submitClickHandle">确认补货</view>
+			<view class="full_screen" v-if="isFullScreen">
+
+			</view>
+		</view>
+
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref,
+	} from 'vue';
+	import {
+		onLoad,
+		onShow,
+		onReachBottom
+	} from "@dcloudio/uni-app";
+
+	import {
+		restockSubmitAPI,
+		fetchMerchantMetalBalanceAPI
+	} from '@/api/merchant';
+
+	import {
+		useImageUpload
+	} from "@/hooks/useImageUpload";
+	import {
+		useToast
+	} from "@/hooks/useToast";
+	import {
+		Debounce
+	} from '@/utils/validate';
+
+
+
+	const {
+		imageList,
+		afterRead,
+		deletePic,
+		uploadLoading
+	} = useImageUpload({
+		pid: 14,
+		model: "recyle",
+	});
+	console.log(imageList.value);
+
+	const {
+		Toast
+	} = useToast();
+
+	const isFullScreen = ref()
+
+	const currentStockType = ref(1)
+	const restockWeight = ref()
+	
+	
+	const auStock = ref({
+		total: 0,
+		useful: 0,
+		used: 0,
+	})
+	const ptStock = ref({
+		total: 0,
+		useful: 0,
+		used: 0,
+	})
+	const agStock = ref({
+		total: 0,
+		useful: 0,
+		used: 0,
+	})
+
+	function onInputChange() {}
+
+	function countDecimalPlaces(num) {
+		const stringNum = String(num);
+		if (stringNum.includes('.')) {
+			return stringNum.split('.')[1].length;
+		} else {
+			return 0;
+		}
+	}
+
+	// 使用同步方法获取系统信息
+	let systemInfo = uni.getSystemInfoSync();
+	console.log(systemInfo);
+
+	// 检查是否为全面屏
+	function isFullScreenFn(systemInfo) {
+		// 通常判断全面屏可以通过比较屏幕高度和窗口高度来决定
+		// 如果屏幕高度大于窗口高度,则可能是刘海屏
+		console.log(systemInfo.screenHeight, systemInfo.windowHeight)
+		return systemInfo.screenHeight > systemInfo.windowHeight;
+	}
+
+	onLoad((params) => {
+		// isFullScreen.value = isFullScreenFn(systemInfo)
+		console.log(params);
+		currentStockType.value = params.type || 1
+		const systemInfo = uni.getSystemInfoSync();
+		try{
+			console.log("Loaded", systemInfo.safeAreaInsets)
+			isFullScreen.value = systemInfo.safeAreaInsets.bottom>0
+		}catch(error){
+			
+		}
+		
+		fetchBalance()
+		
+		// console.log("Loaded", systemInfo.safeAreaInsets)
+
+	})
+
+	let submitting = false
+
+	function submitClickHandle() {
+		if (!restockWeight.value || restockWeight.value <= 0) {
+			return Toast({
+				title: "请输入补货数量"
+			})
+		}
+		// 小数点后有几位,输入数字只支持两位小数
+		const counts = countDecimalPlaces(restockWeight.value);
+		if (counts > 2) {
+			return Toast({
+				title: "补货数量仅支持输入两位小数"
+			})
+		}
+		if (!imageList.value || imageList.value.length == 0) {
+			return Toast({
+				title: "请上传进货凭证"
+			})
+		}
+		if (submitting) return
+		submitting = true;
+		try {
+			restockSubmitAPI({
+				imageUrl: imageList.value[0]?.info?.url || "",
+				metalType: currentStockType.value,
+				restockWeight: restockWeight.value
+			}).then(res => {
+				console.log(res);
+				Toast({
+					title: "补货申请条件成功,正在审核中"
+				})
+				setTimeout(() => {
+					// uni.navigateBack()
+					submitting = false;
+				}, 500)
+
+			}).catch(() => {
+				submitting = false;
+			})
+		} catch (error) {
+			submitting = false;
+			//TODO handle the exception
+		}
+
+	}
+	
+	
+	/**
+	 * 获取当前登录商户金属资产明细
+	 */
+	function fetchBalance() {
+		fetchMerchantMetalBalanceAPI().then(res => {
+			console.log(res)
+			const {
+				data,
+				code
+			} = res
+			console.log(data, code)
+			if (code === 200 && data.length > 0) {
+				data.forEach(item => {
+					console.log(item);
+					switch (item.metalType) {
+						case 1:
+							auStock.value = {
+								total: item.totalIncreaseWeight,
+								useful: item.availableStock,
+								used: item.totalDecreaseWeight
+							}
+							break;
+						case 2:
+							ptStock.value = {
+								total: item.totalIncreaseWeight,
+								useful: item.availableStock,
+								used: item.totalDecreaseWeight
+							}
+							break;
+						case 3:
+							agStock.value = {
+								total: item.totalIncreaseWeight,
+								useful: item.availableStock,
+								used: item.totalDecreaseWeight
+							}
+							break;
+						default:
+							break;
+					}
+				})
+			}
+		}).catch(err => {
+			console.log(err);
+		})
+	}
+</script>
+
+<style scoped lang="scss">
+	uni-page-body {
+		height: 100%;
+	}
+
+	.stock_conatiner {
+		width: 100%;
+		padding: 16rpx;
+		background-color: #F9F7F0;
+	}
+
+	.stock_select_container {
+		background-color: #fff;
+		width: 100%;
+		border-radius: 16rpx;
+
+		.stock_title {
+			font-size: 32rpx;
+			font-weight: bold;
+			padding: 20rpx;
+		}
+
+		.stock_list {
+			display: flex;
+			flex-wrap: nowrap;
+			justify-content: space-between;
+			align-items: flex-start;
+			padding: 0 20rpx 20rpx;
+		}
+
+		.stock_item {
+			display: flex;
+			width: 100rpx;
+			flex: 1;
+			background-color: #F8F7F1;
+			border-radius: 16rpx;
+			border: 2rpx solid transparent;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+			padding-top: 16rpx;
+
+			&.stock_middle {
+				margin: 0 16rpx;
+			}
+
+			&.active {
+				border-color: #F8C008;
+				background-color: rgba(248, 192, 8, 0.10);
+			}
+
+			.stock_icon {
+				width: 72rpx;
+				height: 72rpx;
+			}
+
+			.stock_name {
+				font-size: 28rpx;
+				font-weight: bold;
+				margin: 10rpx 0;
+			}
+
+			.stock_num_title {
+				font-size: 24rpx;
+				padding-bottom: 0;
+				color: #666;
+			}
+
+			.stock_num {
+				font-size: 24rpx;
+				padding-bottom: 14rpx;
+				color: #666;
+			}
+		}
+	}
+
+	.stock_ipt_container {
+		width: 100%;
+		height: 100rpx;
+		background-color: #fff;
+		border-radius: 16rpx;
+		padding: 20rpx;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		flex-wrap: nowrap;
+		margin: 16rpx 0;
+
+		.stock_ipt_title {
+			font-size: 28rpx;
+			color: #333;
+			margin-right: 40rpx;
+		}
+
+
+		.stock_ipt {
+			width: 300rpx;
+			flex: 1;
+			text-align: right;
+			height: 60rpx;
+			line-height: 60rpx;
+			font-size: 28rpx;
+		}
+	}
+
+	.stock_img_upload {
+		background-color: #fff;
+		border-radius: 16rpx;
+		width: 100%;
+		padding: 20rpx;
+
+		.stock_img_title {
+			font-size: 28rpx;
+			color: #333;
+			margin-bottom: 20rpx;
+		}
+
+		.stock_img_tips {
+			font-size: 24rpx;
+			color: #999;
+			line-height: 40rpx;
+			margin-top: 10rpx;
+		}
+	}
+
+	.stock_bottom_btn {
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		width: 100%;
+		// min-height: 132rpx;
+		padding: 22rpx 0;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		background-color: #fff;
+
+		.stock_btn {
+			width: 686rpx;
+			display: block;
+			height: 88rpx;
+			line-height: 88rpx;
+			text-align: center;
+			background-color: #F8C008;
+			border-radius: 16rpx;
+			color: #333;
+			font-size: 32rpx;
+		}
+	}
+
+	.upload-box {
+		width: 682rpx;
+		height: auto;
+		background-color: #ffffff;
+		box-shadow: 0rpx 3rpx 13rpx 0rpx rgba(0, 0, 0, 0.13);
+		border-radius: 20rpx;
+		box-sizing: border-box;
+		margin-top: 25rpx;
+		padding: 40rpx 40rpx;
+
+		.upload-tips {
+			font-size: 26rpx;
+			color: #000000;
+			margin: 30rpx 0;
+		}
+
+		.upload-img {
+			margin: 30rpx 0;
+		}
+
+		.pz-tips {
+			text-align: center;
+			font-size: 24rpx;
+			color: #7c7c7c;
+			margin: 40rpx 0;
+		}
+
+		.pz-img {
+			display: flex;
+			justify-content: space-between;
+			flex-wrap: wrap;
+			margin: 30rpx 0;
+
+			image {
+				width: 138rpx;
+				height: 138rpx;
+				background-color: #f3f3f3;
+				border-radius: 10rpx;
+				margin: 15rpx 0;
+			}
+		}
+	}
+
+	.upload-box-contanier {
+		.upload-block {
+			width: 160rpx;
+			height: 160rpx;
+			border: 1px dashed #ccc;
+			border-radius: 10rpx;
+			display: flex;
+			flex-direction: column;
+			justify-content: center;
+			align-items: center;
+			color: #ccc;
+			background-color: #F9F7F0;
+			font-weight: 700;
+			font-size: 26rpx;
+		}
+	}
+
+	.full_screen {
+		width: 750rpx;
+		height: 32rpx;
+		background-color: #fff;
+	}
+
+	::v-deep .u-upload__wrap__preview {
+		margin: 0;
+	}
+</style>

BIN
static/images/ag_icon.png


BIN
static/images/au_icon.png


BIN
static/images/filter_icon.png


BIN
static/images/pt_icon.png


BIN
static/images/refresh_icon.png


BIN
static/images/warn_icon.png