zbb vor 3 Wochen
Ursprung
Commit
8eb569a7c4
5 geänderte Dateien mit 182 neuen und 311 gelöschten Zeilen
  1. 65 91
      pages/index/index.vue
  2. 52 63
      pages/login/login.vue
  3. 31 60
      pages/mine/card.vue
  4. 31 68
      pages/mine/userCard.vue
  5. 3 29
      utils/poster.js

+ 65 - 91
pages/index/index.vue

@@ -3,9 +3,9 @@
 
 		<!-- 顶部背景 -->
 		<image class="top-bg" src="/static/image/home/top-bg.png" />
-		<NavBar title="" color="#020202" :fixed="true" :bg="'transparent'">
+		<NavBar :title="'我的名片'" :show_back="false" color="#fff" :fixed="true" :bg="'transparent'">
 			<template #left>
-				<view class="left-title">{{appName}}</view>
+				<!-- <view class="left-title">{{appName}}</view> -->
 			</template>
 		</NavBar>
 		<!-- 名片卡片 -->
@@ -48,51 +48,16 @@
 
 
 			<view class="control-card">
-				<view class="item" @click="shareUserCard">
-					<image src="/static/image/public/card-sharing.png"></image>
-					<text class="text">分享名片</text>
-				</view>
-				<view class="item" @click="saveCard">
-					<image src="/static/image/public/card-save.png"></image>
-					<text class="text">保存名片</text>
-				</view>
-				<view class="item" @click="showQRCode">
-					<image src="/static/image/public/card-qr.png"></image>
-					<text class="text">名片码</text>
-				</view>
+				<view class="item" @click="shareUserCard">发名片</view>
 			</view>
 		</view>
 		<view class="card-content">
-			<!-- Tab 切换 -->
-			<view class="tab-section">
-				<view class="tab-wrapper">
-					<!-- 	<view class="tab-item" :class="{ active: currentTab === 'products' }"
-						@click="switchTab('products')">
-						<text class="tab-text">产品列表</text>
-						<view class="tab-indicator" v-if="currentTab === 'products'"></view>
-					</view> -->
-				<!-- 	<view class="tab-item" :class="{ active: currentTab === 'company' }" @click="switchTab('company')">
-						<text class="tab-text">企业简介</text>
-						<view class="tab-indicator" v-if="currentTab === 'company'"></view>
-					</view> -->
-				</view>
-			</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">
-						<text class="product-title">{{ item.title }}</text>
-						<text class="product-desc">{{ item.description }}</text>
-					</view>
-				</view>
-			</view>
 			<!-- 企业简介 -->
-			<view class="company-section" v-if="currentTab === 'company'">
-				<view class="company-content">
-					<rich-text class="company-text" :nodes="companyInfo.introduce"></rich-text>
+			<view class="company-section">
+				<view class="company-title">
+					企业简介
 				</view>
+				<rich-text class="company-text" :nodes="companyInfo.introduce"></rich-text>
 			</view>
 		</view>
 
@@ -236,7 +201,7 @@
 		generateCardPoster,
 		savePosterToAlbum,
 	} from '@/utils/poster.js'
-import {
+	import {
 		getCurrentConfig
 	} from '@/config/index.js'
 	// 使用 Pinia 管理用户状态
@@ -257,16 +222,18 @@ import {
 	const cardPopup = ref(null)
 
 	const productList = ref([])
+	let imageUrl = ref('')
 	onShareAppMessage(() => {
 		return {
 			userName: '小程序',
 			path: 'pages/splash/splash?userId=' + cardInfo.value.userId,
+			imageUrl: imageUrl.value
 		};
 	});
-		let appName = ref('')
+	let appName = ref('')
 	onMounted(async () => {
-			const config = await getCurrentConfig()
-			appName.value = config.appName
+		const config = await getCurrentConfig()
+		appName.value = config.appName
 		// 如果没有数据,重新获取
 		if (!cardInfo.value.nickName) {
 			await userStore.queryCardInfo()
@@ -336,16 +303,24 @@ import {
 
 	const shareUserCard = async () => {
 		const snapshotPath = await generateCardPoster(cardInfo.value, qrInfo.value)
-		wx.showShareImageMenu({
-			path: snapshotPath,
-			entrancePath: 'pages/splash/splash?userId=' + cardInfo.value.userId,
-			success: () => {
-				console.log('分享菜单已调起');
-			},
-			fail: (err) => {
-				console.error('调起分享菜单失败', err);
-			}
-		});
+		imageUrl.value = snapshotPath
+
+
+
+
+
+
+
+		// wx.showShareImageMenu({
+		// 	path: snapshotPath,
+		// 	entrancePath: 'pages/splash/splash?userId=' + cardInfo.value.userId,
+		// 	success: () => {
+		// 		console.log('分享菜单已调起');
+		// 	},
+		// 	fail: (err) => {
+		// 		console.error('调起分享菜单失败', err);
+		// 	}
+		// });
 
 	}
 
@@ -465,6 +440,7 @@ import {
 		color: #ffffff;
 		text-shadow: 2px 2px 0 black;
 	}
+
 	.top-bg {
 		width: 750rpx;
 		height: 634rpx;
@@ -638,25 +614,21 @@ import {
 			display: flex;
 			align-items: center;
 			justify-content: space-around;
-			padding-top: 48rpx;
-			padding-bottom: 24rpx;
+			padding: 48rpx 40rpx 24rpx;
 
 			.item {
 				display: flex;
+				width: 100%;
 				flex-direction: column;
 				align-items: center;
 				justify-content: center;
 				gap: 4rpx;
+				background-color: #155DFC;
+				font-size: 28rpx !important;
+				border-radius: 40rpx;
+				height: 80rpx;
+				color: #fff;
 
-				image {
-					width: 64rpx;
-					height: 64rpx;
-				}
-
-				.text {
-					font-size: 26rpx !important;
-					color: #202020;
-				}
 			}
 		}
 
@@ -666,13 +638,38 @@ import {
 	// 名片内容区域
 	.card-content {
 		margin: 0 24rpx;
-		padding: 0 24rpx;
+		padding: 20rpx 40rpx;
 		border-radius: 24rpx;
 		background: #ffffff;
 		box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.04);
 		position: relative;
 		bottom: 24rpx;
 		z-index: 2;
+		// 企业简介
+		.company-section {
+			background: #ffffff;
+			.company-title{
+				font-weight: bold;
+				font-size: 32rpx;
+				margin-bottom: 12rpx;
+			}
+			.company-text {
+				display: block;
+				font-size: 28rpx;
+				color: #666666;
+				line-height: 1.8;
+				margin-bottom: 24rpx;
+		
+				::v-deep img {
+					max-width: 100% !important;
+					height: auto !important;
+				}
+		
+				&:last-child {
+					margin-bottom: 0;
+				}
+			}
+		}
 	}
 
 	// Tab 切换区域
@@ -758,29 +755,6 @@ import {
 		}
 	}
 
-	// 企业简介
-	.company-section {
-		background: #ffffff;
-		padding: 40rpx;
-
-		.company-content {
-			.company-text {
-				display: block;
-				font-size: 28rpx;
-				color: #666666;
-				line-height: 1.8;
-				margin-bottom: 24rpx;
-
-				::v-deep img {
-					max-width: 100% !important;
-					height: auto !important;
-				}
-				&:last-child {
-					margin-bottom: 0;
-				}
-			}
-		}
-	}
 
 	// 隐藏的 canvas 容器
 	.hidden-canvas-box {

+ 52 - 63
pages/login/login.vue

@@ -4,8 +4,10 @@
 		<view class="nav-bar">
 			<text class="nav-title">登录</text>
 		</view>
+		<!-- 顶部空白区域 -->
+		<view style="height: 100rpx;"></view>
 
-		<!-- Logo 区域 -->
+		<!-- Logo 区域 -->	
 		<view class="logo-section">
 			<image class="logo-icon" src="/static/image/public/logo.png" mode="aspectFill"></image>
 			<text class="app-name">{{appName}}</text>
@@ -27,12 +29,6 @@
 					{{ countdown > 0 ? `${countdown}s` : '获取验证码' }}
 				</text>
 			</view>
-
-			<!-- 登录按钮 -->
-			<view class="login-btn-wrapper">
-				<button class="login-btn" @click="handleLogin" :loading="isLoading">登录</button>
-			</view>
-
 			<!-- 协议说明 -->
 			<view class="agreement-text">
 				<text class="gray-text">登录即代表您已同意</text>
@@ -40,33 +36,22 @@
 				<text class="gray-text">与</text>
 				<text class="link-text" @click="showPrivacyPolicy">《隐私政策》</text>
 			</view>
-		</view>
-
-		<!-- 其他登录方式 -->
-		<view class="other-method-section">
-			<view class="divider">
-				<view class="divider-line"></view>
-				<text class="divider-text">其他方式</text>
-				<view class="divider-line"></view>
+			<!-- 登录按钮 -->
+			<view class="login-btn-wrapper">
+				<button class="login-btn" @click="handleLogin" :loading="isLoading">登录</button>
 			</view>
-
-			<!-- 微信一键登录 -->
+			<!-- #ifdef MP-WEIXIN -->
 			<view class="wechat-login-wrapper">
-				<!-- #ifdef MP-WEIXIN -->
 				<button class="wechat-login-btn" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
 					<image class="wechat-icon-img" src="/static/image/public/wechat-icon.png" mode="aspectFit" />
 					<text class="wechat-text">微信一键登录</text>
 				</button>
-				<!-- #endif -->
-				<!-- #ifndef MP-WEIXIN -->
-				<button class="wechat-login-btn" @click="wechatLogin">
-					<text class="wechat-icon"></text>
-					<text class="wechat-text">微信一键登录</text>
-				</button>
-				<!-- #endif -->
 			</view>
+			<!-- #endif -->
 		</view>
 
+
+
 		<!-- 用户协议弹窗 -->
 		<view class="agreement-popup" v-if="showUserAgreementPopup" @click="closeUserAgreement">
 			<view class="popup-mask"></view>
@@ -250,11 +235,11 @@
 			if (token) {
 				// 调用 store 里的函数获取名片和公司信息
 				saveToekn(token)
-			let cardInfo = 	await userStore.queryCardInfo()
+				let cardInfo = await userStore.queryCardInfo()
 				await userStore.queryCompanyInfo()
 				await userStore.queryCardQrcode()
-				console.log(cardInfo,"cardInfocardInfocardInfo");
-				
+				console.log(cardInfo, "cardInfocardInfocardInfo");
+
 				uni.showToast({
 					title: '登录成功',
 					icon: 'success'
@@ -427,18 +412,19 @@
 		margin-bottom: 80rpx;
 
 		.logo-icon {
-			width: 160rpx;
-			height: 160rpx;
+			width: 132rpx;
+			height: 132rpx;
 			background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
 			border-radius: 32rpx;
 			box-shadow: 0 8rpx 24rpx rgba(24, 144, 255, 0.3);
 		}
 
 		.app-name {
-			font-size: 40rpx;
-			font-weight: 600;
-			color: #000000;
-			margin-top: 32rpx;
+			margin-top: 42rpx;
+			font-size: 48rpx;
+			font-weight: bold;
+			text-align: LEFT;
+			color: #101828;
 		}
 	}
 
@@ -458,7 +444,7 @@
 		.verify-code-row {
 			display: flex;
 			align-items: center;
-
+			gap: 6rpx;
 			.code-input {
 				flex: 1;
 				margin-right: 20rpx;
@@ -539,38 +525,41 @@
 			}
 		}
 
-		.wechat-login-wrapper {
-			.wechat-login-btn {
-				width: 100%;
-				height: 88rpx;
-				background: linear-gradient(90deg, #07c160 0%, #06ad56 100%);
-				border-radius: 16rpx;
-				border: none;
-				font-size: 32rpx;
-				font-weight: 500;
-				color: #ffffff;
-				display: flex;
-				align-items: center;
-				justify-content: center;
 
-				&::after {
-					border: none;
-				}
 
-				.wechat-icon-img {
-					width: 40rpx;
-					height: 40rpx;
-					margin-right: 12rpx;
-				}
+	}
 
-				.wechat-icon {
-					margin-right: 12rpx;
-					font-size: 36rpx;
-				}
+	.wechat-login-wrapper {
+		.wechat-login-btn {
+			width: 100%;
+			height: 88rpx;
+			background: linear-gradient(90deg, #1890ff 0%, #096dd9 100%);
+			border-radius: 16rpx;
+			border: none;
+			font-size: 32rpx;
+			font-weight: 500;
+			color: #ffffff;
+			display: flex;
+			align-items: center;
+			justify-content: center;
 
-				.wechat-text {
-					color: #ffffff;
-				}
+			&::after {
+				border: none;
+			}
+
+			.wechat-icon-img {
+				width: 40rpx;
+				height: 40rpx;
+				margin-right: 12rpx;
+			}
+
+			.wechat-icon {
+				margin-right: 12rpx;
+				font-size: 36rpx;
+			}
+
+			.wechat-text {
+				color: #ffffff;
 			}
 		}
 	}

+ 31 - 60
pages/mine/card.vue

@@ -58,47 +58,18 @@
 			</view>
 		</view>
 		<view class="card-content">
-			<!-- Tab 切换 -->
-			<view class="tab-section">
-				<view class="tab-wrapper">
-				<!-- 	<view class="tab-item" :class="{ active: currentTab === 'products' }"
-						@click="switchTab('products')">
-						<text class="tab-text">产品列表</text>
-						<view class="tab-indicator" v-if="currentTab === 'products'"></view>
-					</view> -->
-			<!-- 		<view class="tab-item" :class="{ active: currentTab === 'company' }" @click="switchTab('company')">
-						<text class="tab-text">企业简介</text>
-						<view class="tab-indicator" v-if="currentTab === 'company'"></view>
-					</view> -->
-				</view>
-			</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">
-						<text class="product-title">{{ item.title }}</text>
-						<text class="product-desc">{{ item.description }}</text>
-					</view>
-				</view>
-			</view>
 			<!-- 企业简介 -->
-			<view class="company-section" v-if="currentTab === 'company'">
-				<view class="company-content">
-					<rich-text class="company-text" :nodes="companyInfo.introduce"></rich-text>
+			<view class="company-section">
+				<view class="company-title">
+					企业简介
 				</view>
+				<rich-text class="company-text" :nodes="companyInfo.introduce"></rich-text>
 			</view>
 		</view>
 
 		<!-- 隐藏的 Canvas 用于生成名片快照 -->
 		<canvas id="posterCanvas" type="2d"
-			style="position: fixed; left: -9999px; top: -9999px; width: 750px; height: 900px;"></canvas>
+			style="position: fixed; left: -9999px; top: -9999px; width: 750px; height: 600px;"></canvas>
 
 		<!-- 隐藏的 Canvas 用于生成二维码海报 -->
 		<view class="hidden-canvas-box">
@@ -695,17 +666,41 @@
 
 
 	}
-
 	// 名片内容区域
 	.card-content {
 		margin: 0 24rpx;
-		padding: 0 24rpx;
+		padding: 20rpx 40rpx;
 		border-radius: 24rpx;
 		background: #ffffff;
 		box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.04);
 		position: relative;
 		bottom: 24rpx;
 		z-index: 2;
+		// 企业简介
+		.company-section {
+			background: #ffffff;
+			.company-title{
+				font-weight: bold;
+				font-size: 32rpx;
+				margin-bottom: 12rpx;
+			}
+			.company-text {
+				display: block;
+				font-size: 28rpx;
+				color: #666666;
+				line-height: 1.8;
+				margin-bottom: 24rpx;
+		
+				::v-deep img {
+					max-width: 100% !important;
+					height: auto !important;
+				}
+		
+				&:last-child {
+					margin-bottom: 0;
+				}
+			}
+		}
 	}
 
 	// Tab 切换区域
@@ -791,30 +786,6 @@
 		}
 	}
 
-	// 企业简介
-	.company-section {
-		background: #ffffff;
-		padding: 40rpx;
-
-		.company-content {
-			.company-text {
-				display: block;
-				font-size: 28rpx;
-				color: #666666;
-				line-height: 1.8;
-				margin-bottom: 24rpx;
-
-				::v-deep img {
-					max-width: 100% !important;
-					height: auto !important;
-				}
-
-				&:last-child {
-					margin-bottom: 0;
-				}
-			}
-		}
-	}
 
 	// 隐藏的 canvas 容器
 	.hidden-canvas-box {

+ 31 - 68
pages/mine/userCard.vue

@@ -41,52 +41,14 @@
 					</view>
 				</view>
 			</view>
-			<!-- 		<view class="control-card">
-				<view class="item">
-					<image src="/static/image/public/card-sharing.png"></image>
-					<text>分享名片</text>
-				</view>
-				<view class="item">
-					<image src="/static/image/public/card-save.png"></image>
-					<text>保存名片</text>
-				</view>
-				<view class="item">
-					<image src="/static/image/public/card-qr.png"></image>
-					<text>名片码</text>
-				</view>
-			</view> -->
 		</view>
 		<view class="card-content">
-			<!-- Tab 切换 -->
-			<view class="tab-section">
-				<view class="tab-wrapper">
-				<!-- 	<view class="tab-item" :class="{ active: currentTab === 'products' }"
-						@click="switchTab('products')">
-						<text class="tab-text">产品列表</text>
-						<view class="tab-indicator" v-if="currentTab === 'products'"></view>
-					</view> -->
-				<!-- 	<view class="tab-item" :class="{ active: currentTab === 'company' }" @click="switchTab('company')">
-						<text class="tab-text">企业简介</text>
-						<view class="tab-indicator" v-if="currentTab === 'company'"></view>
-					</view> -->
-				</view>
-			</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">
-						<text class="product-title">{{ item.title }}</text>
-						<text class="product-desc">{{ item.description }}</text>
-					</view>
-				</view>
-			</view> -->
 			<!-- 企业简介 -->
-			<view class="company-section" v-if="currentTab === 'company'">
-				<view class="company-content">
-					<rich-text class="company-text" :nodes="companyInfo.introduce"></rich-text>
+			<view class="company-section">
+				<view class="company-title">
+					企业简介
 				</view>
+				<rich-text class="company-text" :nodes="companyInfo.introduce"></rich-text>
 			</view>
 		</view>
 	</view>
@@ -385,12 +347,38 @@
 	// 名片内容区域
 	.card-content {
 		margin: 0 24rpx;
-		padding: 0 24rpx;
+		padding: 20rpx 40rpx;
 		border-radius: 24rpx;
 		background: #ffffff;
 		box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.04);
 		position: relative;
+		bottom: 24rpx;
 		z-index: 2;
+		// 企业简介
+		.company-section {
+			background: #ffffff;
+			.company-title{
+				font-weight: bold;
+				font-size: 32rpx;
+				margin-bottom: 12rpx;
+			}
+			.company-text {
+				display: block;
+				font-size: 28rpx;
+				color: #666666;
+				line-height: 1.8;
+				margin-bottom: 24rpx;
+		
+				::v-deep img {
+					max-width: 100% !important;
+					height: auto !important;
+				}
+		
+				&:last-child {
+					margin-bottom: 0;
+				}
+			}
+		}
 	}
 
 	// Tab 切换区域
@@ -475,29 +463,4 @@
 			}
 		}
 	}
-
-	// 企业简介
-	.company-section {
-		background: #ffffff;
-		padding: 40rpx;
-
-		.company-content {
-			.company-text {
-				display: block;
-				font-size: 28rpx;
-				color: #666666;
-				line-height: 1.8;
-				margin-bottom: 24rpx;
-
-				::v-deep img {
-					max-width: 100% !important;
-					height: auto !important;
-				}
-
-				&:last-child {
-					margin-bottom: 0;
-				}
-			}
-		}
-	}
 </style>

+ 3 - 29
utils/poster.js

@@ -5,7 +5,7 @@
  */
 
 const W = 750
-const H = 820
+const H = 600
 const PADDING = 40
 
 const roundRect = (ctx, x, y, w, h, r) => {
@@ -201,7 +201,7 @@ export const generateCardPoster = async (cardInfo = {}, qrInfo = {}) => {
 
 				// ===== 3. 白色卡片 =====
 				const cardX = PADDING, cardY = 60
-				const cardW = W - PADDING * 2, cardH = 700
+				const cardW = W - PADDING * 2, cardH = 480
 				ctx.save()
 				ctx.shadowColor = 'rgba(0,0,0,0.08)'
 				ctx.shadowBlur = 24
@@ -317,33 +317,7 @@ export const generateCardPoster = async (cardInfo = {}, qrInfo = {}) => {
 				drawContactRow(ctx, '✉', cardInfo.email, contactX, contactY + 20 + contactGap)
 				drawContactRow(ctx, '📍', cardInfo.companyAddress, contactX, contactY + 20 + contactGap * 2)
 
-				// ===== 8. 底部名片码 =====
-				const qrBoxSize = 130
-				const cardInnerBottom = cardY + cardH - 32
-				const qrBoxX = innerX + innerW - qrBoxSize - 44
-				const qrBoxY = cardInnerBottom - qrBoxSize - 44
-
-				// 灰色圆角背景框
-				ctx.save()
-				ctx.fillStyle = '#F5F7FA'
-				roundRect(ctx, qrBoxX - 8, qrBoxY - 8, qrBoxSize + 16, qrBoxSize + 16, 12)
-				ctx.fill()
-				ctx.restore()
-
-				// 加载二维码图片(使用 canvas.createImage())
-				try {
-					const qrLocalPath = await qrBase64ToTempFile(qrInfo.image)
-					if (qrLocalPath) {
-						const qrImg = await createCanvasImage(canvas, qrLocalPath)
-						if (qrImg) {
-							ctx.drawImage(qrImg, qrBoxX, qrBoxY, qrBoxSize, qrBoxSize)
-						}
-					}
-				} catch (e) {
-					console.warn('加载名片码失败:', e)
-				}
-
-				// ===== 9. 导出 =====
+				// ===== 8. 导出 =====
 				setTimeout(() => {
 					uni.canvasToTempFilePath({
 						canvas,