zbb 1 Minggu lalu
induk
melakukan
244325ba02

+ 175 - 0
components/empty-state/index.vue

@@ -0,0 +1,175 @@
+<template>
+	<view class="empty-state" :style="containerStyle">
+		<!-- 空状态图标 -->
+		<view class="empty-icon-box" :style="iconBoxStyle">
+			<image
+				v-if="image"
+				class="empty-image"
+				:src="image"
+				mode="aspectFit"
+			/>
+			<uni-icons
+				v-else
+				:type="icon"
+				:size="iconSize"
+				:color="iconColor"
+			></uni-icons>
+		</view>
+		<!-- 提示文字 -->
+		<text class="empty-text" :style="textStyle">{{ text }}</text>
+		<!-- 副文字(可选) -->
+		<text v-if="subText" class="empty-sub-text">{{ subText }}</text>
+		<!-- 操作按钮(可选) -->
+		<view v-if="showBtn" class="empty-btn" :style="btnStyle" @click="handleClick">
+			<text class="empty-btn-text">{{ btnText }}</text>
+		</view>
+	</view>
+</template>
+
+<script setup>
+import { computed } from 'vue'
+
+const props = defineProps({
+	// 提示文字
+	text: {
+		type: String,
+		default: '暂无数据'
+	},
+	// 副文字
+	subText: {
+		type: String,
+		default: ''
+	},
+	// 图标名称(uni-icons type)
+	icon: {
+		type: String,
+		default: 'list'
+	},
+	// 图标大小
+	iconSize: {
+		type: Number,
+		default: 80
+	},
+	// 图标颜色
+	iconColor: {
+		type: String,
+		default: '#CCCCCC'
+	},
+	// 自定义图片(优先级高于icon)
+	image: {
+		type: String,
+		default: ''
+	},
+	// 是否显示按钮
+	showBtn: {
+		type: Boolean,
+		default: false
+	},
+	// 按钮文字
+	btnText: {
+		type: String,
+		default: '刷新'
+	},
+	// 按钮颜色
+	btnColor: {
+		type: String,
+		default: '#4080FF'
+	},
+	// 上边距(rpx)
+	marginTop: {
+		type: Number,
+		default: 120
+	},
+	// 下边距(rpx)
+	marginBottom: {
+		type: Number,
+		default: 0
+	}
+})
+
+const emit = defineEmits(['click'])
+
+const containerStyle = computed(() => {
+	return {
+		marginTop: (props.marginTop / 2) + 'px',
+		marginBottom: (props.marginBottom / 2) + 'px'
+	}
+})
+
+const iconBoxStyle = computed(() => {
+	return {
+		width: (props.iconSize * 1.5 / 2) + 'px',
+		height: (props.iconSize * 1.5 / 2) + 'px'
+	}
+})
+
+const textStyle = computed(() => {
+	return {
+		color: '#999999'
+	}
+})
+
+const btnStyle = computed(() => {
+	return {
+		backgroundColor: props.btnColor
+	}
+})
+
+const handleClick = () => {
+	emit('click')
+}
+</script>
+
+<style scoped>
+.empty-state {
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	justify-content: center;
+	padding: 60rpx 40rpx;
+}
+
+.empty-icon-box {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	margin-bottom: 32rpx;
+	border-radius: 50%;
+	background: #f5f6f8;
+}
+
+.empty-image {
+	width: 100%;
+	height: 100%;
+}
+
+.empty-text {
+	font-size: 28rpx;
+	color: #999999;
+	line-height: 1.5;
+	text-align: center;
+}
+
+.empty-sub-text {
+	font-size: 24rpx;
+	color: #BBBBBB;
+	margin-top: 12rpx;
+	text-align: center;
+	line-height: 1.5;
+}
+
+.empty-btn {
+	margin-top: 40rpx;
+	padding: 16rpx 56rpx;
+	border-radius: 40rpx;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+}
+
+.empty-btn-text {
+	font-size: 28rpx;
+	color: #FFFFFF;
+	font-weight: 500;
+}
+</style>

+ 8 - 1
pages/message/index.vue

@@ -10,6 +10,13 @@
 		</view>
 
 		<scroll-view class="message-list" scroll-y>
+			<!-- 空状态 -->
+			<EmptyState
+				v-if="messageList.length === 0"
+				text="暂无消息"
+				sub-text="暂时没有新的消息"
+				icon="chatbubble"
+			/>
 			<view class="message-item" v-for="(item, index) in messageList" :key="index" @click="viewDetail">
 				<view class="message-icon">
 					<uni-icons type="bell" size="24" color="#1890ff"></uni-icons>
@@ -31,7 +38,7 @@
 		ref,
 		reactive
 	} from 'vue'
-
+	import EmptyState from '@/components/empty-state/index.vue'
 	const currentTab = ref('system')
 
 	const messageList = reactive([])

+ 8 - 1
pages/mine/card.vue

@@ -45,7 +45,7 @@
 			<view class="control-card">
 				<view class="item" @click="shareUserCard">
 					<image src="/static/image/public/card-sharing.png"></image>
-					<button open-type="share" class="text resetButton">分享名片</button>
+					<text class="text">分享名片</text>
 				</view>
 				<view class="item" @click="saveCard">
 					<image src="/static/image/public/card-save.png"></image>
@@ -74,6 +74,12 @@
 			</view>
 			<!-- 产品列表 -->
 			<view class="product-list" v-if="currentTab === 'products'">
+				<EmptyState
+					v-if="productList.length === 0"
+					text="暂无产品"
+					sub-text="还没有添加产品信息"
+					icon="gift"
+				/>
 				<view class="product-item" v-for="(item, index) in productList" :key="index">
 					<image class="product-image" :src="item.image" mode="aspectFill" />
 					<view class="product-info">
@@ -219,6 +225,7 @@
 	} from '@dcloudio/uni-app';
 	import NavBar from '@/components/nav-bar/index.vue'
 	import UserAvatar from '@/components/user-avatar/index.vue'
+	import EmptyState from '@/components/empty-state/index.vue'
 	import {
 		useUserStore
 	} from '@/store/modules/user.js'

+ 13 - 1
pages/mine/userCard.vue

@@ -21,7 +21,8 @@
 
 				<!-- 右上:头像 -->
 				<view class="avatar-wrapper">
-					<UserAvatar :src="cardInfo.avatar" :name="cardInfo.nickName" :size="130" :badge-src="'/static/image/public/badge-icon.png'" :badge-size="56" />
+					<UserAvatar :src="cardInfo.avatar" :name="cardInfo.nickName" :size="130"
+						:badge-src="'/static/image/public/badge-icon.png'" :badge-size="56" />
 				</view>
 
 				<!-- 左下:联系方式 -->
@@ -72,6 +73,7 @@
 			</view>
 			<!-- 产品列表 -->
 			<view class="product-list" v-if="currentTab === 'products'">
+				<EmptyState v-if="productList.length === 0" text="暂无产品" sub-text="还没有添加产品信息" icon="gift" />
 				<view class="product-item" v-for="(item, index) in productList" :key="index">
 					<image class="product-image" :src="item.image" mode="aspectFill" />
 					<view class="product-info">
@@ -95,8 +97,12 @@
 		ref,
 		onMounted
 	} from 'vue'
+	import {
+		onShareAppMessage
+	} from '@dcloudio/uni-app';
 	import NavBar from '@/components/nav-bar/index.vue'
 	import UserAvatar from '@/components/user-avatar/index.vue'
+	import EmptyState from '@/components/empty-state/index.vue'
 	import {
 		useUserStore
 	} from '@/store/modules/user.js'
@@ -125,6 +131,12 @@
 		}
 	})
 
+	onShareAppMessage(() => {
+		return {
+			userName: '小程序',
+			path: 'pages/splash/splash?userId=' + cardInfo.value.userId,
+		};
+	});
 	const makeCall = () => {
 		if (cardInfo.value.phonenumber) {
 			uni.makePhoneCall({

+ 36 - 5
pages/todos/index.vue

@@ -50,7 +50,13 @@
 		
 	
 		<scroll-view v-if="currentTab === 'leads'" class="content-scroll" scroll-y>
-			<view class="leads-list">
+			<EmptyState
+				v-if="leadsList.length === 0"
+				text="暂无线索"
+				sub-text="暂时没有新的线索信息"
+				icon="person"
+			/>
+			<view class="leads-list" v-else>
 				<view class="leads-item" v-for="(item, index) in leadsList" :key="index" @click="viewDetail">
 					<view class="row-title">
 						<text class="title-text">{{ item.title }}</text>
@@ -73,7 +79,13 @@
 		</scroll-view>
 
 		<scroll-view v-else-if="currentTab === 'customer'" class="content-scroll" scroll-y>
-			<view class="customer-list">
+			<EmptyState
+				v-if="customerList.length === 0"
+				text="暂无客户"
+				sub-text="暂时没有客户信息"
+				icon="contact"
+			/>
+			<view class="customer-list" v-else>
 				<view class="company-group" v-for="(company, index) in customerList" :key="index">
 					<view class="company-header" @click="viewDetail">
 						<text class="company-name">{{ company.name }}</text>
@@ -93,7 +105,13 @@
 		</scroll-view>
 
 		<scroll-view v-else-if="currentTab === 'opportunity'" class="content-scroll" scroll-y>
-			<view class="opportunity-list">
+			<EmptyState
+				v-if="opportunityList.length === 0"
+				text="暂无商机"
+				sub-text="暂时没有商机信息"
+				icon="flag"
+			/>
+			<view class="opportunity-list" v-else>
 				<view class="opportunity-item" v-for="(item, index) in opportunityList" :key="index"
 					@click="viewDetail">
 					<view class="opp-header">
@@ -115,7 +133,13 @@
 		</scroll-view>
 
 		<scroll-view v-else-if="currentTab === 'contract'" class="content-scroll" scroll-y>
-			<view class="contract-list">
+			<EmptyState
+				v-if="contractList.length === 0"
+				text="暂无合同"
+				sub-text="暂时没有合同信息"
+				icon="paperclip"
+			/>
+			<view class="contract-list" v-else>
 				<view class="contract-item" v-for="(item, index) in contractList" :key="index" @click="viewDetail">
 					<view class="contract-header">
 						<text class="contract-title">{{ item.title }}</text>
@@ -134,7 +158,13 @@
 		</scroll-view>
 
 		<scroll-view v-else-if="currentTab === 'payment'" class="content-scroll" scroll-y>
-			<view class="payment-list">
+			<EmptyState
+				v-if="paymentList.length === 0"
+				text="暂无回款"
+				sub-text="暂时没有回款记录"
+				icon="wallet"
+			/>
+			<view class="payment-list" v-else>
 				<view class="payment-item" v-for="(item, index) in paymentList" :key="index" @click="viewDetail">
 					<view class="payment-header">
 						<text class="payment-title">{{ item.title }}</text>
@@ -160,6 +190,7 @@
 
 <script setup>
 	import NavBar from '@/components/nav-bar/index.vue'
+	import EmptyState from '@/components/empty-state/index.vue'
 	import {
 		ref,
 		reactive