|
|
@@ -1,5 +1,6 @@
|
|
|
<template>
|
|
|
- <view class="index-container">
|
|
|
+ <view class="card-container">
|
|
|
+
|
|
|
<!-- 顶部背景 -->
|
|
|
<image class="top-bg" src="/static/image/home/top-bg.png" />
|
|
|
<NavBar title="" color="#020202" :fixed="true" :bg="'transparent'">
|
|
|
@@ -7,247 +8,224 @@
|
|
|
<view class="left-title">{{appName}}</view>
|
|
|
</template>
|
|
|
</NavBar>
|
|
|
- <view class="page-warp">
|
|
|
- <view class="page-top">
|
|
|
- <view class="user-card">
|
|
|
- <!-- 背景图 -->
|
|
|
- <image class="user-card-bg" src="/static/image/home/usecard-bg.png" />
|
|
|
-
|
|
|
- <!-- 左上:姓名 + 职位 -->
|
|
|
- <view class="user-header">
|
|
|
- <view class="name-row">
|
|
|
- <text class="user-name">{{ cardInfo.nickName || '用户' }}</text>
|
|
|
- <text class="user-role">{{ cardInfo.postName || '职位' }}</text>
|
|
|
- </view>
|
|
|
- <text class="company-name">{{ cardInfo.companyName || '公司名称' }}</text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 右上:头像 -->
|
|
|
- <view class="avatar-wrapper">
|
|
|
- <UserAvatar :src="cardInfo.avatar" :name="cardInfo.nickName" :size="140" :badge-src="'/static/image/public/badge-icon.png'" :badge-size="64" />
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 左下:联系方式 -->
|
|
|
- <view class="user-contact">
|
|
|
- <view class="contact-row" @click="makeCall">
|
|
|
- <uni-icons style="margin-top: 4rpx;" type="phone" :size="18" color="#666666"></uni-icons>
|
|
|
- <text class="contact-text">{{ cardInfo.phonenumber || '暂无电话' }}</text>
|
|
|
- </view>
|
|
|
- <view class="contact-row">
|
|
|
- <uni-icons style="margin-top: 4rpx;" type="email" :size="18" color="#666666"></uni-icons>
|
|
|
- <text class="contact-text">{{ cardInfo.email || '暂无邮箱' }}</text>
|
|
|
- </view>
|
|
|
- <view class="contact-row">
|
|
|
- <uni-icons style="margin-top: 4rpx;" type="location" :size="18" color="#666666"></uni-icons>
|
|
|
- <text class="contact-text">{{ cardInfo.companyAddress || '暂无地址' }}</text>
|
|
|
- </view>
|
|
|
+ <!-- 名片卡片 -->
|
|
|
+ <view class="page-top">
|
|
|
+ <view class="user-card" id="user-card">
|
|
|
+ <!-- 背景图 -->
|
|
|
+ <image class="user-card-bg" src="/static/image/home/usecard-bg.png" />
|
|
|
+
|
|
|
+ <!-- 左上:姓名 + 职位 -->
|
|
|
+ <view class="user-header">
|
|
|
+ <view class="name-row">
|
|
|
+ <text class="user-name">{{ cardInfo.nickName || '用户' }}</text>
|
|
|
+ <text class="user-role">{{ cardInfo.postName || '职位' }}</text>
|
|
|
</view>
|
|
|
+ <text class="company-name">{{ cardInfo.companyName || '公司名称' }}</text>
|
|
|
+ </view>
|
|
|
|
|
|
- <!-- 右下:分享名片按钮 -->
|
|
|
- <!-- <view class="share-btn-wrapper">
|
|
|
- <view class="share-btn" @click="shareCard">
|
|
|
- <text class="share-text">分享名片</text>
|
|
|
- </view>
|
|
|
- </view> -->
|
|
|
+ <!-- 右上:头像 -->
|
|
|
+ <view class="avatar-wrapper">
|
|
|
+ <UserAvatar :src="cardInfo.avatar" :name="cardInfo.nickName" :size="130"
|
|
|
+ :badge-src="'/static/image/public/badge-icon.png'" :badge-size="56" />
|
|
|
</view>
|
|
|
- </view>
|
|
|
|
|
|
- <!-- 最近访客模块 -->
|
|
|
- <view class="recent-visitors" v-if="false">
|
|
|
- <view class="section-header">
|
|
|
- <text class="section-title">最近访客</text>
|
|
|
- <view class="visitor-count">
|
|
|
- <view class="avatar-group">
|
|
|
- <image class="group-avatar" src="/static/avatar-1.png" mode="aspectFill" />
|
|
|
- <image class="group-avatar" src="/static/avatar-2.png" mode="aspectFill" />
|
|
|
- <image class="group-avatar" src="/static/avatar-3.png" mode="aspectFill" />
|
|
|
- </view>
|
|
|
- <text class="visitor-number">255 人</text>
|
|
|
+ <!-- 左下:联系方式 -->
|
|
|
+ <view class="user-contact">
|
|
|
+ <view class="contact-row" @click="makeCall">
|
|
|
+ <uni-icons type="phone" :size="18" color="#666666"></uni-icons>
|
|
|
+ <text class="contact-text">{{ cardInfo.phonenumber || '暂无电话' }}</text>
|
|
|
</view>
|
|
|
- </view>
|
|
|
- <view class="visitor-list">
|
|
|
- <view class="visitor-item">
|
|
|
- <view class="visitor-left">
|
|
|
- <view class="visitor-top">
|
|
|
- <view class="visitor-avatar">
|
|
|
- <image src="/static/image/public/avatar-default2.png" mode="aspectFill" />
|
|
|
- </view>
|
|
|
- <view class="visitor-name-row">
|
|
|
- <text class="visitor-name">匿名用户</text>
|
|
|
- <text class="visitor-tag pending">待跟进</text>
|
|
|
- </view>
|
|
|
- <view class="view-more-btn" @click="viewAllVisitors">查看更多</view>
|
|
|
- </view>
|
|
|
- <view class="visitor-meta">
|
|
|
- <text class="meta-item">
|
|
|
- <text class="meta-label">来源:</text>
|
|
|
- <text class="meta-value">微信小程序</text>
|
|
|
- </text>
|
|
|
- <text class="meta-item">
|
|
|
- <text class="meta-label">手机:</text>
|
|
|
- <text class="meta-value">13822255555</text>
|
|
|
- </text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <view class="visitor-product">
|
|
|
- <image class="product-image" src="/static/product-printer.png" mode="aspectFit" />
|
|
|
- <view class="product-info">
|
|
|
- <text class="product-name">惠普黑白激光打印机 选配小白盒巴</text>
|
|
|
- <view>
|
|
|
- <text class="product-tag">打印机</text>
|
|
|
- <text class="product-brand">惠普</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
+ <view class="contact-row">
|
|
|
+ <uni-icons type="email" :size="18" color="#666666"></uni-icons>
|
|
|
+ <text class="contact-text">{{ cardInfo.email || '暂无邮箱' }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="contact-row">
|
|
|
+ <uni-icons type="location" :size="18" color="#666666"></uni-icons>
|
|
|
+ <text class="contact-text">{{ cardInfo.companyAddress || '暂无地址' }}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
- <!-- 底部拖动条 -->
|
|
|
- <view class="drag-handle"></view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 功能菜单网格 -->
|
|
|
- <view class="function-grid" v-if="false">
|
|
|
- <view class="grid-item" @click="navigateTo('clue')">
|
|
|
- <view class="grid-icon clue-icon">
|
|
|
- <text class="icon-text">📋</text>
|
|
|
- </view>
|
|
|
- <text class="grid-label">线索管理</text>
|
|
|
+
|
|
|
+ <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="grid-item" @click="navigateTo('customer')">
|
|
|
- <view class="grid-icon customer-icon">
|
|
|
- <text class="icon-text">🏢</text>
|
|
|
- </view>
|
|
|
- <text class="grid-label">客户管理</text>
|
|
|
+ <view class="item" @click="saveCard">
|
|
|
+ <image src="/static/image/public/card-save.png"></image>
|
|
|
+ <text class="text">保存名片</text>
|
|
|
</view>
|
|
|
- <view class="grid-item" @click="navigateTo('contact')">
|
|
|
- <view class="grid-icon contact-icon">
|
|
|
- <text class="icon-text">👥</text>
|
|
|
- </view>
|
|
|
- <text class="grid-label">联系人管理</text>
|
|
|
- </view>
|
|
|
- <view class="grid-item" @click="navigateTo('public-pool')">
|
|
|
- <view class="grid-icon pool-icon">
|
|
|
- <text class="icon-text">🌊</text>
|
|
|
- </view>
|
|
|
- <text class="grid-label">客户公海</text>
|
|
|
+ <view class="item" @click="showQRCode">
|
|
|
+ <image src="/static/image/public/card-qr.png"></image>
|
|
|
+ <text class="text">名片码</text>
|
|
|
</view>
|
|
|
- <view class="grid-item" @click="navigateTo('opportunity')">
|
|
|
- <view class="grid-icon opportunity-icon">
|
|
|
- <text class="icon-text">💼</text>
|
|
|
- </view>
|
|
|
- <text class="grid-label">商机管理</text>
|
|
|
- </view>
|
|
|
- <view class="grid-item" @click="navigateTo('payment')">
|
|
|
- <view class="grid-icon payment-icon">
|
|
|
- <text class="icon-text">💰</text>
|
|
|
+ </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>
|
|
|
- <text class="grid-label">回款管理</text>
|
|
|
</view>
|
|
|
- <view class="grid-item" @click="navigateTo('product')">
|
|
|
- <view class="grid-icon product-icon">
|
|
|
- <text class="icon-text">📦</text>
|
|
|
+ </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>
|
|
|
- <text class="grid-label">产品管理</text>
|
|
|
</view>
|
|
|
- <view class="grid-item" @click="navigateTo('all')">
|
|
|
- <view class="grid-icon all-icon">
|
|
|
- <text class="icon-text">📊</text>
|
|
|
- </view>
|
|
|
- <text class="grid-label">全部</text>
|
|
|
+ </view>
|
|
|
+ <!-- 企业简介 -->
|
|
|
+ <view class="company-section" v-if="currentTab === 'company'">
|
|
|
+ <view class="company-content">
|
|
|
+ <rich-text class="company-text" :nodes="companyInfo.introduce"></rich-text>
|
|
|
</view>
|
|
|
</view>
|
|
|
+ </view>
|
|
|
|
|
|
- <!-- 业务日历模块 -->
|
|
|
- <view class="business-calendar" v-if="false">
|
|
|
- <view class="section-header">
|
|
|
- <text class="section-title">业务日历</text>
|
|
|
- <text class="view-more" @click="viewAllCalendar">查看更多</text>
|
|
|
- </view>
|
|
|
+ <!-- 隐藏的 Canvas 用于生成名片快照 -->
|
|
|
+ <canvas id="posterCanvas" type="2d"
|
|
|
+ style="position: fixed; left: -9999px; top: -9999px; width: 750px; height: 780px;"></canvas>
|
|
|
+
|
|
|
+ <!-- 隐藏的 Canvas 用于生成二维码海报 -->
|
|
|
+ <view class="hidden-canvas-box">
|
|
|
+ <canvas id="qrPosterCanvas" type="2d" style="width: 600px; height: 700px;"></canvas>
|
|
|
+ </view>
|
|
|
|
|
|
- <!-- 日历头部 -->
|
|
|
- <view class="calendar-header">
|
|
|
- <text class="calendar-month">2026 年 4 月</text>
|
|
|
+ <!-- 名片分享弹窗 -->
|
|
|
+ <uni-popup ref="cardPopup" type="center">
|
|
|
+ <view class="card-popup">
|
|
|
+ <!-- 顶部装饰条 -->
|
|
|
+ <view class="popup-decor">
|
|
|
+ <view class="decor-line"></view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 星期 -->
|
|
|
- <view class="calendar-weekdays">
|
|
|
- <text class="weekday">日</text>
|
|
|
- <text class="weekday">一</text>
|
|
|
- <text class="weekday">二</text>
|
|
|
- <text class="weekday">三</text>
|
|
|
- <text class="weekday">四</text>
|
|
|
- <text class="weekday">五</text>
|
|
|
- <text class="weekday">六</text>
|
|
|
+ <!-- 标题 -->
|
|
|
+ <view class="popup-title-box">
|
|
|
+ <text class="popup-title">我的名片</text>
|
|
|
+ <text class="popup-desc">分享给朋友或保存到相册</text>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 日期网格 -->
|
|
|
- <view class="calendar-dates">
|
|
|
- <view class="date-cell">
|
|
|
- <text class="date-num">15</text>
|
|
|
- </view>
|
|
|
- <view class="date-cell">
|
|
|
- <text class="date-num">16</text>
|
|
|
- </view>
|
|
|
- <view class="date-cell">
|
|
|
- <text class="date-num">17</text>
|
|
|
+ <!-- 名片卡片 -->
|
|
|
+ <view class="card-box">
|
|
|
+ <view class="user-card">
|
|
|
+ <!-- 背景图 -->
|
|
|
+ <image class="user-card-bg" src="/static/image/home/usecard-bg.png" mode="aspectFill" />
|
|
|
+
|
|
|
+ <!-- 左上:姓名 + 职位 -->
|
|
|
+ <view class="user-header">
|
|
|
+ <view class="name-row">
|
|
|
+ <text class="user-name">{{ cardInfo.nickName || '用户' }}</text>
|
|
|
+ <text class="user-role">{{ cardInfo.postName || '职位' }}</text>
|
|
|
+ </view>
|
|
|
+ <text class="company-name">{{ cardInfo.companyName || '公司名称' }}</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 右上:头像 -->
|
|
|
+ <view class="user-avatar-box">
|
|
|
+ <UserAvatar :src="cardInfo.avatar" :name="cardInfo.nickName" :size="120"
|
|
|
+ :badge-src="'/static/image/public/badge-icon.png'" :badge-size="50" />
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 左下:联系方式 -->
|
|
|
+ <view class="user-contact">
|
|
|
+ <view class="contact-row" @click="makeCall">
|
|
|
+ <view class="contact-icon">
|
|
|
+ <uni-icons type="phone" :size="16" color="#4080FF"></uni-icons>
|
|
|
+ </view>
|
|
|
+ <text class="contact-text">{{ cardInfo.phonenumber || '暂无电话' }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="contact-row">
|
|
|
+ <view class="contact-icon">
|
|
|
+ <uni-icons type="email" :size="16" color="#4080FF"></uni-icons>
|
|
|
+ </view>
|
|
|
+ <text class="contact-text">{{ cardInfo.email || '暂无邮箱' }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="contact-row">
|
|
|
+ <view class="contact-icon">
|
|
|
+ <uni-icons type="location" :size="16" color="#4080FF"></uni-icons>
|
|
|
+ </view>
|
|
|
+ <text class="contact-text">{{ cardInfo.companyAddress || '暂无地址' }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <view class="date-cell today">
|
|
|
- <text class="date-num current">18</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 操作按钮 -->
|
|
|
+ <view class="popup-btns">
|
|
|
+ <view class="btn btn-cancel" @click="closeCardPopup">
|
|
|
+ <text class="btn-text">取消</text>
|
|
|
</view>
|
|
|
- <view class="date-cell has-event">
|
|
|
- <text class="date-num">19</text>
|
|
|
- <view class="event-dot"></view>
|
|
|
+ <view class="btn btn-confirm" @click="shareCardConfirm">
|
|
|
+ <text class="btn-text">分享名片</text>
|
|
|
</view>
|
|
|
- <view class="date-cell">
|
|
|
- <text class="date-num">20</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 底部全宽按钮 -->
|
|
|
+ <view class="popup-footer">
|
|
|
+ <view class="btn btn-full" @click="shareCardConfirm">
|
|
|
+ <uni-icons type="paperplane" size="22" color="#ffffff"></uni-icons>
|
|
|
+ <text class="btn-text">立即分享名片给朋友</text>
|
|
|
</view>
|
|
|
- <view class="date-cell">
|
|
|
- <text class="date-num">21</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </uni-popup>
|
|
|
+
|
|
|
+ <!-- 二维码弹窗 -->
|
|
|
+ <uni-popup ref="qrPopup" type="center">
|
|
|
+ <view class="qr-popup">
|
|
|
+ <view class="qr-header">
|
|
|
+ <text class="qr-title">名片二维码</text>
|
|
|
+ <text class="qr-subtitle">扫一扫查看我的名片信息</text>
|
|
|
+ </view>
|
|
|
+ <view class="qr-content">
|
|
|
+ <image v-if="qrInfo && qrInfo.image"
|
|
|
+ :src="qrInfo.image.startsWith('data:') ? qrInfo.image : 'data:image/png;base64,' + qrInfo.image"
|
|
|
+ class="qr-image" mode="aspectFit" />
|
|
|
+ <view v-else class="qr-loading">
|
|
|
+ <text>加载中...</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
-
|
|
|
- <!-- 今日日程 -->
|
|
|
- <view class="today-schedule">
|
|
|
- <view class="schedule-item">
|
|
|
- <view class="schedule-time">
|
|
|
- <text class="time-period">下午</text>
|
|
|
- <text class="time-value">3:00</text>
|
|
|
- </view>
|
|
|
- <view class="schedule-content">
|
|
|
- <text class="schedule-title">与李总沟通合同细节</text>
|
|
|
- </view>
|
|
|
+ <view class="qr-actions">
|
|
|
+ <view class="action-btn" @click="saveQRCode">
|
|
|
+ <uni-icons type="download" size="24" color="#4080FF"></uni-icons>
|
|
|
+ <text class="action-text">保存到相册</text>
|
|
|
</view>
|
|
|
- <view class="schedule-item tomorrow">
|
|
|
- <view class="schedule-time">
|
|
|
- <text class="time-period">明天</text>
|
|
|
- <text class="time-value">10:00</text>
|
|
|
- </view>
|
|
|
- <view class="schedule-content">
|
|
|
- <text class="schedule-title">拜访新客户 - 科技公司</text>
|
|
|
- </view>
|
|
|
+ <view class="action-btn" @click="handleShare">
|
|
|
+ <uni-icons type="paperplane" size="24" color="#4080FF"></uni-icons>
|
|
|
+ <!-- <button open-type="share" class="action-text">分享给好友</button> -->
|
|
|
+ <text class="action-text">分享给好友</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
-
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 底部留白,避免被 TabBar 遮挡 -->
|
|
|
- <view class="bottom-spacer"></view>
|
|
|
-
|
|
|
- <!-- 名片预览弹窗 -->
|
|
|
- <CardPreview :visible="showPreview" @close="closePreview" @share="handleShareCard" @save="handleSaveCard" />
|
|
|
+ </uni-popup>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
- import NavBar from '@/components/nav-bar/index.vue'
|
|
|
- import UserAvatar from '@/components/user-avatar/index.vue'
|
|
|
- import CardPreview from './components/card-preview.vue'
|
|
|
import {
|
|
|
ref,
|
|
|
- onMounted,
|
|
|
- computed
|
|
|
+ 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'
|
|
|
@@ -255,34 +233,47 @@
|
|
|
storeToRefs
|
|
|
} from 'pinia'
|
|
|
import {
|
|
|
+ generateCardPoster,
|
|
|
+ savePosterToAlbum,
|
|
|
+ } from '@/utils/poster.js'
|
|
|
+import {
|
|
|
getCurrentConfig
|
|
|
} from '@/config/index.js'
|
|
|
// 使用 Pinia 管理用户状态
|
|
|
const userStore = useUserStore()
|
|
|
const {
|
|
|
cardInfo,
|
|
|
- companyInfo
|
|
|
+ companyInfo,
|
|
|
+ qrInfo,
|
|
|
} = storeToRefs(userStore)
|
|
|
|
|
|
- let appName = ref('')
|
|
|
-
|
|
|
+ const currentTab = ref('company')
|
|
|
+ // 名片快照图片路径
|
|
|
+ const cardSnapshot = ref('')
|
|
|
+ // 二维码海报图片路径
|
|
|
+ const qrCodePoster = ref('')
|
|
|
+ // 二维码弹窗引用
|
|
|
+ const qrPopup = ref(null)
|
|
|
+ const cardPopup = ref(null)
|
|
|
+
|
|
|
+ const productList = ref([])
|
|
|
+ onShareAppMessage(() => {
|
|
|
+ return {
|
|
|
+ userName: '小程序',
|
|
|
+ path: 'pages/splash/splash?userId=' + cardInfo.value.userId,
|
|
|
+ };
|
|
|
+ });
|
|
|
+ let appName = ref('')
|
|
|
onMounted(async () => {
|
|
|
- const config = await getCurrentConfig()
|
|
|
- appName.value = config.appName
|
|
|
- // 从 store 中获取用户名片和公司信息
|
|
|
- console.log('用户名片信息:', cardInfo.value)
|
|
|
- console.log('公司信息:', companyInfo.value)
|
|
|
-
|
|
|
- // 如果没有数据,重新获取
|
|
|
+ const config = await getCurrentConfig()
|
|
|
+ appName.value = config.appName
|
|
|
+ // 如果没有数据,重新获取
|
|
|
if (!cardInfo.value.nickName) {
|
|
|
await userStore.queryCardInfo()
|
|
|
}
|
|
|
if (!companyInfo.value.name) {
|
|
|
await userStore.queryCompanyInfo()
|
|
|
}
|
|
|
-
|
|
|
- console.log('更新后的用户名片信息:', cardInfo.value)
|
|
|
- console.log('更新后的公司信息:', companyInfo.value)
|
|
|
})
|
|
|
|
|
|
const makeCall = () => {
|
|
|
@@ -298,57 +289,174 @@
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 控制名片预览弹窗
|
|
|
- const showPreview = ref(false)
|
|
|
+ // 生成名片快照并保存
|
|
|
+ const saveCard = async () => {
|
|
|
+ uni.showLoading({
|
|
|
+ title: '生成快照中...',
|
|
|
+ mask: true
|
|
|
+ })
|
|
|
+
|
|
|
+ try {
|
|
|
+
|
|
|
+ // 生成名片快照
|
|
|
+ const snapshotPath = await generateCardPoster(cardInfo.value, qrInfo.value)
|
|
|
+ console.log(snapshotPath, "snapshotPathsnapshotPathsnapshotPath");
|
|
|
+ // 用属性接收快照路径
|
|
|
+ cardSnapshot.value = snapshotPath
|
|
|
|
|
|
- const shareCard = () => {
|
|
|
- showPreview.value = true
|
|
|
+ console.log('名片快照路径:', cardSnapshot.value)
|
|
|
+
|
|
|
+ // 保存到相册
|
|
|
+ await savePosterToAlbum(snapshotPath)
|
|
|
+
|
|
|
+ uni.hideLoading()
|
|
|
+ uni.showToast({
|
|
|
+ title: '已保存到相册',
|
|
|
+ icon: 'success'
|
|
|
+ })
|
|
|
+ } catch (error) {
|
|
|
+ console.error('保存失败:', error)
|
|
|
+ uni.hideLoading()
|
|
|
+ uni.showToast({
|
|
|
+ title: '保存失败,请重试',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- // 关闭预览弹窗
|
|
|
- const closePreview = () => {
|
|
|
- showPreview.value = false
|
|
|
+ // 显示二维码
|
|
|
+ const showQRCode = async () => {
|
|
|
+ // 打开弹窗
|
|
|
+ qrPopup.value.open()
|
|
|
}
|
|
|
|
|
|
- // 分享名片
|
|
|
- const handleShareCard = () => {
|
|
|
- uni.showShareMenu({
|
|
|
- withShareTicket: true
|
|
|
- })
|
|
|
+ const close = async () => {
|
|
|
+ cardPopup.value.close()
|
|
|
}
|
|
|
|
|
|
- // 保存名片
|
|
|
- const handleSaveCard = () => {
|
|
|
- uni.showToast({
|
|
|
- title: '已保存到手机相册',
|
|
|
- icon: 'success'
|
|
|
- })
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- const viewAllVisitors = () => {
|
|
|
- uni.navigateTo({
|
|
|
- url: '/pages/visitors/list'
|
|
|
+
|
|
|
+ const base64ToImage = async (base64Data) => {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ try {
|
|
|
+ const filePath = `${wx.env.USER_DATA_PATH}/temp_image.png`;
|
|
|
+ let pureBase64Data = base64Data
|
|
|
+ if (pureBase64Data.startsWith('data:image')) {
|
|
|
+ pureBase64Data = pureBase64Data.replace(/^data:image\/\w+;base64,/, '');
|
|
|
+ }
|
|
|
+ const fs = wx.getFileSystemManager();
|
|
|
+ fs.writeFile({
|
|
|
+ filePath: filePath,
|
|
|
+ data: pureBase64Data,
|
|
|
+ encoding: 'base64',
|
|
|
+ success: (res) => {
|
|
|
+ console.log("resresweresresresres", res);
|
|
|
+ resolve(filePath)
|
|
|
+ },
|
|
|
+ fail: (err) => {
|
|
|
+ console.error('写入临时文件失败', err);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('base64 转换异常:', error)
|
|
|
+ reject(error)
|
|
|
+ }
|
|
|
})
|
|
|
}
|
|
|
+ const handleShare = async () => {
|
|
|
+ const qrFilePath = await base64ToTempFile(qrInfo.value.image)
|
|
|
+ wx.showShareImageMenu({
|
|
|
+ path: qrFilePath,
|
|
|
+ entrancePath: 'pages/splash/splash?userId=' + cardInfo.value.userId,
|
|
|
+ success: () => {
|
|
|
+ console.log('分享菜单已调起');
|
|
|
+ },
|
|
|
+ fail: (err) => {
|
|
|
+ console.error('调起分享菜单失败', err);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // 保存二维码到相册
|
|
|
+ const saveQRCode = async () => {
|
|
|
+ if (!qrInfo.value.image) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '二维码图片不存在',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
- const navigateTo = (page) => {
|
|
|
- uni.showToast({
|
|
|
- title: `功能开发中:${page}`,
|
|
|
- icon: 'none'
|
|
|
- })
|
|
|
+ try {
|
|
|
+ // 将 base64 转换为临时文件
|
|
|
+ const qrFilePath = await base64ToTempFile(qrInfo.value.image)
|
|
|
+ // 保存到相册
|
|
|
+ await savePosterToAlbum(qrFilePath)
|
|
|
+ uni.showToast({
|
|
|
+ title: '已保存到相册',
|
|
|
+ icon: 'success'
|
|
|
+ })
|
|
|
+ } catch (error) {
|
|
|
+ console.error('保存失败:', error)
|
|
|
+ uni.showToast({
|
|
|
+ title: '保存失败,请重试',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- const viewAllCalendar = () => {
|
|
|
- uni.navigateTo({
|
|
|
- url: '/pages/calendar/list'
|
|
|
+
|
|
|
+
|
|
|
+ const switchTab = (tab) => {
|
|
|
+ currentTab.value = tab
|
|
|
+ }
|
|
|
+ // 将 base64 转换为临时文件路径
|
|
|
+ const base64ToTempFile = async (base64Data) => {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ try {
|
|
|
+ // 移除 data:image/png;base64, 前缀(如果有)
|
|
|
+ const pureBase64 = base64Data.replace(/^data:image\/\w+;base64,/, '')
|
|
|
+
|
|
|
+ const fileName = `${Date.now()}_qrcode.png`
|
|
|
+ const filePath = `${wx.env.USER_DATA_PATH}/${fileName}`
|
|
|
+ const fs = uni.getFileSystemManager()
|
|
|
+ fs.writeFile({
|
|
|
+ filePath: filePath,
|
|
|
+ data: pureBase64,
|
|
|
+ encoding: 'base64',
|
|
|
+ success: () => {
|
|
|
+ console.log('base64 转文件成功:', filePath)
|
|
|
+ resolve(filePath)
|
|
|
+ },
|
|
|
+ fail: (err) => {
|
|
|
+ console.error('base64 转文件失败:', err)
|
|
|
+ reject(err)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } catch (error) {
|
|
|
+ console.error('base64 转换异常:', error)
|
|
|
+ reject(error)
|
|
|
+ }
|
|
|
})
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
- .index-container {
|
|
|
- background-color: #f5f6f8;
|
|
|
- padding-bottom: 120rpx;
|
|
|
+ .card-container {
|
|
|
+ background: #f5f6f8;
|
|
|
}
|
|
|
|
|
|
.left-title {
|
|
|
@@ -357,7 +465,6 @@
|
|
|
color: #ffffff;
|
|
|
text-shadow: 2px 2px 0 black;
|
|
|
}
|
|
|
-
|
|
|
.top-bg {
|
|
|
width: 750rpx;
|
|
|
height: 634rpx;
|
|
|
@@ -367,517 +474,410 @@
|
|
|
z-index: 1;
|
|
|
}
|
|
|
|
|
|
- .page-warp {
|
|
|
+ // 顶部背景区域
|
|
|
+ .header-bg {
|
|
|
+ background: linear-gradient(135deg, #4A90E2 0%, #6FB3F2 50%, #87CEEB 100%);
|
|
|
+ padding: 0 40rpx;
|
|
|
+ padding-top: calc(var(--status-bar-height) + 20rpx);
|
|
|
+ padding-bottom: 60rpx;
|
|
|
position: relative;
|
|
|
- z-index: 2;
|
|
|
- padding: 20px;
|
|
|
- }
|
|
|
-
|
|
|
- /* 用户信息卡片 */
|
|
|
- .page-top {
|
|
|
- margin-bottom: 20rpx;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ // 背景光效
|
|
|
+ &::before {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ top: -100rpx;
|
|
|
+ right: -100rpx;
|
|
|
+ width: 500rpx;
|
|
|
+ height: 500rpx;
|
|
|
+ background: radial-gradient(circle, rgba(255, 255, 255, 0.2) 0%, transparent 70%);
|
|
|
+ border-radius: 50%;
|
|
|
+ }
|
|
|
|
|
|
- .user-card {
|
|
|
- width: 100%;
|
|
|
- height: 414rpx;
|
|
|
- padding: 80rpx 40rpx 32rpx;
|
|
|
+ // 导航栏
|
|
|
+ .nav-bar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ height: 88rpx;
|
|
|
position: relative;
|
|
|
+ z-index: 10;
|
|
|
|
|
|
- .user-card-bg {
|
|
|
- position: absolute;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- z-index: 0;
|
|
|
+ .nav-back {
|
|
|
+ width: 60rpx;
|
|
|
+ height: 60rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
}
|
|
|
|
|
|
- view,
|
|
|
- text {
|
|
|
- position: relative;
|
|
|
- z-index: 1;
|
|
|
+ .nav-title {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #ffffff;
|
|
|
+ text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
|
|
}
|
|
|
|
|
|
- .user-header {
|
|
|
- .name-row {
|
|
|
+ .nav-right {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ .more-btn,
|
|
|
+ .refresh-btn {
|
|
|
+ width: 64rpx;
|
|
|
+ height: 64rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: rgba(255, 255, 255, 0.15);
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- margin-bottom: 16rpx;
|
|
|
+ justify-content: center;
|
|
|
+ margin-left: 16rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- .user-name {
|
|
|
- font-size: 44rpx;
|
|
|
- font-weight: 700;
|
|
|
- color: #202020;
|
|
|
- line-height: 1.2;
|
|
|
- }
|
|
|
|
|
|
- .user-role {
|
|
|
- margin-left: 16rpx;
|
|
|
- padding: 6rpx 16rpx;
|
|
|
- background: rgba(68, 110, 255, 0.10);
|
|
|
- border-radius: 8rpx;
|
|
|
- font-size: 24rpx;
|
|
|
- font-weight: 500;
|
|
|
- color: #446eff;
|
|
|
- }
|
|
|
+ .user-card {
|
|
|
+ position: relative;
|
|
|
+ z-index: 2;
|
|
|
+ width: 100%;
|
|
|
+ height: 400rpx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 80rpx 40rpx 32rpx;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ .user-card-bg {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ z-index: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ view,
|
|
|
+ text {
|
|
|
+ position: relative;
|
|
|
+ z-index: 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .user-header {
|
|
|
+ .name-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+
|
|
|
+ .user-name {
|
|
|
+ font-size: 44rpx;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #202020;
|
|
|
+ line-height: 1.2;
|
|
|
}
|
|
|
|
|
|
- .company-name {
|
|
|
- font-size: 28rpx;
|
|
|
+ .user-role {
|
|
|
+ margin-left: 16rpx;
|
|
|
+ padding: 6rpx 16rpx;
|
|
|
+ background: rgba(68, 110, 255, 0.10);
|
|
|
+ border-radius: 8rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
font-weight: 500;
|
|
|
- color: #666666;
|
|
|
- line-height: 1.4;
|
|
|
+ color: #446eff;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- .avatar-wrapper {
|
|
|
- position: absolute;
|
|
|
- top: 32rpx;
|
|
|
- right: 36rpx;
|
|
|
- z-index: 2;
|
|
|
+ .company-name {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #666666;
|
|
|
+ line-height: 1.4;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- .user-contact {
|
|
|
- margin-top: 32rpx;
|
|
|
+ .avatar-wrapper {
|
|
|
+ position: absolute;
|
|
|
+ top: 32rpx;
|
|
|
+ right: 36rpx;
|
|
|
+ z-index: 2;
|
|
|
+ }
|
|
|
|
|
|
- .contact-row {
|
|
|
- display: flex;
|
|
|
- align-items: flex-start;
|
|
|
- margin-bottom: 16rpx;
|
|
|
+ .user-contact {
|
|
|
+ margin-top: 32rpx;
|
|
|
|
|
|
- uni-icons {
|
|
|
- margin-right: 12rpx;
|
|
|
- flex-shrink: 0;
|
|
|
- }
|
|
|
+ .contact-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
|
|
|
- .contact-text {
|
|
|
- font-size: 26rpx;
|
|
|
- color: #666666;
|
|
|
- }
|
|
|
+ uni-icons {
|
|
|
+ margin-right: 12rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- .share-btn-wrapper {
|
|
|
- position: absolute;
|
|
|
- bottom: 90rpx;
|
|
|
- right: 40rpx;
|
|
|
-
|
|
|
- .share-btn {
|
|
|
- padding: 14rpx 36rpx;
|
|
|
- background: linear-gradient(90deg, #446dff 0%, #6b85ff 100%);
|
|
|
- border-radius: 32rpx;
|
|
|
- box-shadow: 0 4rpx 12rpx rgba(68, 110, 255, 0.35);
|
|
|
-
|
|
|
- .share-text {
|
|
|
- font-size: 26rpx;
|
|
|
- font-weight: 500;
|
|
|
- color: #ffffff;
|
|
|
- }
|
|
|
+ .contact-text {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #666666;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- /* 最近访客模块 */
|
|
|
- .recent-visitors {
|
|
|
- padding: 20rpx;
|
|
|
- background: #f2f6ff;
|
|
|
- border: 2rpx solid rgba(255, 255, 255, 0.80);
|
|
|
- border-radius: 28rpx;
|
|
|
+ /* 用户信息卡片 */
|
|
|
+ .page-top {
|
|
|
+ margin: 0 24rpx 24rpx;
|
|
|
+
|
|
|
|
|
|
- .section-header {
|
|
|
+ .control-card {
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 0 0 24rpx 24rpx;
|
|
|
+ position: relative;
|
|
|
+ z-index: 1;
|
|
|
+ bottom: 24rpx;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- margin-bottom: 24rpx;
|
|
|
-
|
|
|
- .section-title {
|
|
|
- font-size: 32rpx;
|
|
|
- font-weight: 600;
|
|
|
- color: #333333;
|
|
|
- }
|
|
|
+ justify-content: space-around;
|
|
|
+ padding-top: 48rpx;
|
|
|
+ padding-bottom: 24rpx;
|
|
|
|
|
|
- .visitor-count {
|
|
|
+ .item {
|
|
|
display: flex;
|
|
|
+ flex-direction: column;
|
|
|
align-items: center;
|
|
|
- margin-left: 20rpx;
|
|
|
-
|
|
|
- .avatar-group {
|
|
|
- display: flex;
|
|
|
- margin-right: 12rpx;
|
|
|
-
|
|
|
- .group-avatar {
|
|
|
- width: 32rpx;
|
|
|
- height: 32rpx;
|
|
|
- border-radius: 50%;
|
|
|
- border: 4rpx solid #ffffff;
|
|
|
- margin-left: -16rpx;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 4rpx;
|
|
|
|
|
|
- &:first-child {
|
|
|
- margin-left: 0;
|
|
|
- }
|
|
|
- }
|
|
|
+ image {
|
|
|
+ width: 64rpx;
|
|
|
+ height: 64rpx;
|
|
|
}
|
|
|
|
|
|
- .visitor-number {
|
|
|
- font-size: 24rpx;
|
|
|
- color: #999999;
|
|
|
+ .text {
|
|
|
+ font-size: 26rpx !important;
|
|
|
+ color: #202020;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- .view-more {
|
|
|
- font-size: 24rpx;
|
|
|
- color: #667eea;
|
|
|
- margin-left: auto;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
- .visitor-list {
|
|
|
- background: #ffffff;
|
|
|
- border: 2rpx solid #ffffff;
|
|
|
- border-radius: 28rpx;
|
|
|
|
|
|
- .visitor-item {
|
|
|
- padding: 20rpx;
|
|
|
+ }
|
|
|
|
|
|
- .visitor-left {
|
|
|
- display: grid;
|
|
|
+ // 名片内容区域
|
|
|
+ .card-content {
|
|
|
+ margin: 0 24rpx;
|
|
|
+ padding: 0 24rpx;
|
|
|
+ border-radius: 24rpx;
|
|
|
+ background: #ffffff;
|
|
|
+ box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.04);
|
|
|
+ position: relative;
|
|
|
+ bottom: 24rpx;
|
|
|
+ z-index: 2;
|
|
|
+ }
|
|
|
|
|
|
- .visitor-top {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: auto 1fr auto;
|
|
|
- gap: 6rpx;
|
|
|
- }
|
|
|
+ // Tab 切换区域
|
|
|
+ .tab-section {
|
|
|
+ border-radius: 24rpx 24rpx 0 0;
|
|
|
+ padding: 0 40rpx;
|
|
|
|
|
|
- .visitor-name-row {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
-
|
|
|
- .visitor-name {
|
|
|
- font-size: 24rpx;
|
|
|
- font-weight: 500;
|
|
|
- color: #8390b1;
|
|
|
- margin: 0 10rpx;
|
|
|
- }
|
|
|
-
|
|
|
- .visitor-tag {
|
|
|
- width: 92rpx;
|
|
|
- height: 40rpx;
|
|
|
- text-align: center;
|
|
|
- line-height: 40rpx;
|
|
|
- border: 1.2rpx solid #ff9230;
|
|
|
- border-radius: 12rpx;
|
|
|
- font-size: 24rpx;
|
|
|
- font-weight: 500;
|
|
|
- color: #ff9230;
|
|
|
- }
|
|
|
- }
|
|
|
+ .tab-wrapper {
|
|
|
+ display: flex;
|
|
|
+ border-bottom: 1rpx solid #f0f0f0;
|
|
|
|
|
|
- .view-more-btn {
|
|
|
- font-size: 24rpx;
|
|
|
- color: #999999;
|
|
|
- }
|
|
|
+ .tab-item {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ padding: 32rpx 0;
|
|
|
+ position: relative;
|
|
|
|
|
|
- .visitor-avatar {
|
|
|
- width: 40rpx;
|
|
|
- height: 40rpx;
|
|
|
- border-radius: 50%;
|
|
|
- background: #ffffff;
|
|
|
- padding: 4rpx;
|
|
|
- box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
|
|
|
-
|
|
|
- image {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- border-radius: 50%;
|
|
|
- }
|
|
|
- }
|
|
|
+ .tab-text {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #999999;
|
|
|
+ font-weight: 500;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
- .visitor-meta {
|
|
|
- display: flex;
|
|
|
- align-items: flex-start;
|
|
|
- margin-bottom: 16rpx;
|
|
|
- gap: 32rpx;
|
|
|
-
|
|
|
- .meta-item {
|
|
|
- display: flex;
|
|
|
- align-items: flex-start;
|
|
|
-
|
|
|
- .meta-label {
|
|
|
- font-size: 22rpx;
|
|
|
- color: #999999;
|
|
|
- }
|
|
|
-
|
|
|
- .meta-value {
|
|
|
- font-size: 22rpx;
|
|
|
- color: #666666;
|
|
|
- }
|
|
|
- }
|
|
|
+ &.active .tab-text {
|
|
|
+ color: #333333;
|
|
|
+ font-weight: 600;
|
|
|
}
|
|
|
|
|
|
- .visitor-product {
|
|
|
- display: flex;
|
|
|
- align-items: flex-start;
|
|
|
- background: #ffffff;
|
|
|
- border-radius: 16rpx;
|
|
|
- padding: 16rpx;
|
|
|
- box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
|
|
-
|
|
|
- .product-image {
|
|
|
- width: 72rpx;
|
|
|
- height: 72rpx;
|
|
|
- border-radius: 12rpx;
|
|
|
- background-color: #30cfd0;
|
|
|
- margin-right: 16rpx;
|
|
|
- }
|
|
|
-
|
|
|
- .product-info {
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- justify-content: center;
|
|
|
-
|
|
|
- .product-name {
|
|
|
- font-size: 24rpx;
|
|
|
- font-weight: 500;
|
|
|
- color: #08105c;
|
|
|
- }
|
|
|
-
|
|
|
- .product-tag,
|
|
|
- .product-brand {
|
|
|
- font-size: 20rpx;
|
|
|
- color: #999999;
|
|
|
- margin-right: 12rpx;
|
|
|
- }
|
|
|
- }
|
|
|
+ .tab-indicator {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ width: 60rpx;
|
|
|
+ height: 4rpx;
|
|
|
+ background: linear-gradient(90deg, #4A90E2 0%, #6FB3F2 100%);
|
|
|
+ border-radius: 2rpx;
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- .drag-handle {
|
|
|
- width: 80rpx;
|
|
|
- height: 8rpx;
|
|
|
- background: rgba(0, 0, 0, 0.2);
|
|
|
- border-radius: 4rpx;
|
|
|
- margin: 24rpx auto 0;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
- /* 功能菜单网格 */
|
|
|
- .function-grid {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: repeat(4, 1fr);
|
|
|
- gap: 24rpx;
|
|
|
- margin-top: 20rpx;
|
|
|
- padding: 32rpx 24rpx;
|
|
|
- height: 322rpx;
|
|
|
- background: linear-gradient(180deg, #eff6ff, #ffffff 42%);
|
|
|
- border: 2rpx solid #ffffff;
|
|
|
- border-radius: 28rpx;
|
|
|
- box-shadow: 0rpx 8rpx 8rpx 0rpx rgba(178, 194, 208, 0.10);
|
|
|
-
|
|
|
- .grid-item {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
+ // 产品列表
|
|
|
+ .product-list {
|
|
|
+ padding: 24rpx 40rpx;
|
|
|
|
|
|
- .grid-icon {
|
|
|
- width: 54rpx;
|
|
|
- height: 54rpx;
|
|
|
- border-radius: 28rpx;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- margin-bottom: 12rpx;
|
|
|
-
|
|
|
- .icon-text {
|
|
|
- font-size: 48rpx;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .clue-icon {
|
|
|
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
- }
|
|
|
-
|
|
|
- .customer-icon {
|
|
|
- background: linear-gradient(135deg, #30cfd0 0%, #330867 100%);
|
|
|
- }
|
|
|
+ .product-item {
|
|
|
+ display: flex;
|
|
|
+ padding: 24rpx 0;
|
|
|
+ border-bottom: 1rpx solid #f0f0f0;
|
|
|
|
|
|
- .contact-icon {
|
|
|
- background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
|
|
|
+ &:last-child {
|
|
|
+ border-bottom: none;
|
|
|
}
|
|
|
|
|
|
- .pool-icon {
|
|
|
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
+ .product-image {
|
|
|
+ width: 160rpx;
|
|
|
+ height: 160rpx;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ background: #f5f5f5;
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-right: 24rpx;
|
|
|
}
|
|
|
|
|
|
- .opportunity-icon {
|
|
|
- background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
|
|
- }
|
|
|
+ .product-info {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
|
|
|
- .payment-icon {
|
|
|
- background: linear-gradient(135deg, #ffd89b 0%, #19547b 100%);
|
|
|
- }
|
|
|
+ .product-title {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333333;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+ line-height: 1.5;
|
|
|
+ }
|
|
|
|
|
|
- .product-icon {
|
|
|
- background: linear-gradient(135deg, #89f7fe 0%, #66a6ff 100%);
|
|
|
+ .product-desc {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #999999;
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- .all-icon {
|
|
|
- background: linear-gradient(135deg, #cd9cf2 0%, #f6f3ff 100%);
|
|
|
- }
|
|
|
+ // 企业简介
|
|
|
+ .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;
|
|
|
+ }
|
|
|
|
|
|
- .grid-label {
|
|
|
- font-size: 24rpx;
|
|
|
- color: #333333;
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /* 业务日历模块 */
|
|
|
- .business-calendar {
|
|
|
+ // 隐藏的 canvas 容器
|
|
|
+ .hidden-canvas-box {
|
|
|
+ position: fixed;
|
|
|
+ left: -9999px;
|
|
|
+ top: -9999px;
|
|
|
+ width: 1px;
|
|
|
+ height: 1px;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 二维码弹窗样式
|
|
|
+ .qr-popup {
|
|
|
+ margin: 100rpx auto;
|
|
|
+
|
|
|
+ width: 600rpx;
|
|
|
background: #ffffff;
|
|
|
- margin: 20rpx 0;
|
|
|
- padding: 32rpx;
|
|
|
border-radius: 24rpx;
|
|
|
- box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
|
|
|
+ padding: 40rpx;
|
|
|
+ box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.15);
|
|
|
|
|
|
- .section-header {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- margin-bottom: 24rpx;
|
|
|
+ .qr-header {
|
|
|
+ text-align: center;
|
|
|
+ margin-bottom: 40rpx;
|
|
|
|
|
|
- .section-title {
|
|
|
- font-size: 32rpx;
|
|
|
+ .qr-title {
|
|
|
+ display: block;
|
|
|
+ font-size: 36rpx;
|
|
|
font-weight: 600;
|
|
|
- color: #333333;
|
|
|
+ color: #202020;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
}
|
|
|
|
|
|
- .view-more {
|
|
|
- font-size: 24rpx;
|
|
|
- color: #667eea;
|
|
|
+ .qr-subtitle {
|
|
|
+ display: block;
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #999999;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- .calendar-header {
|
|
|
- text-align: center;
|
|
|
- margin-bottom: 20rpx;
|
|
|
+ .qr-content {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ min-height: 400rpx;
|
|
|
+ margin-bottom: 40rpx;
|
|
|
|
|
|
- .calendar-month {
|
|
|
- font-size: 30rpx;
|
|
|
- font-weight: 600;
|
|
|
- color: #333333;
|
|
|
+ .qr-image {
|
|
|
+ width: 400rpx;
|
|
|
+ height: 400rpx;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- .calendar-weekdays {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: repeat(7, 1fr);
|
|
|
- text-align: center;
|
|
|
- margin-bottom: 16rpx;
|
|
|
-
|
|
|
- .weekday {
|
|
|
- font-size: 24rpx;
|
|
|
- color: #999999;
|
|
|
- padding: 12rpx 0;
|
|
|
+ .qr-loading {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- .calendar-dates {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: repeat(7, 1fr);
|
|
|
- gap: 8rpx;
|
|
|
- margin-bottom: 32rpx;
|
|
|
+ .qr-actions {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-around;
|
|
|
|
|
|
- .date-cell {
|
|
|
- aspect-ratio: 1;
|
|
|
+ .action-btn {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
- justify-content: center;
|
|
|
- border-radius: 50%;
|
|
|
- position: relative;
|
|
|
-
|
|
|
- .date-num {
|
|
|
- font-size: 26rpx;
|
|
|
- color: #333333;
|
|
|
- }
|
|
|
-
|
|
|
- &.today {
|
|
|
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
+ gap: 12rpx;
|
|
|
+ padding: 20rpx 40rpx;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ background: rgba(64, 128, 255, 0.08);
|
|
|
|
|
|
- .date-num {
|
|
|
- color: #ffffff;
|
|
|
- font-weight: 600;
|
|
|
+ .action-text {
|
|
|
+ &::after {
|
|
|
+ border: none;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- &.has-event {
|
|
|
- .event-dot {
|
|
|
- width: 12rpx;
|
|
|
- height: 12rpx;
|
|
|
- background: #ff6b6b;
|
|
|
- border-radius: 50%;
|
|
|
- position: absolute;
|
|
|
- bottom: 8rpx;
|
|
|
- }
|
|
|
+ line-height: 1;
|
|
|
+ background-color: transparent;
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #4080FF;
|
|
|
+ font-weight: 500;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- .today-schedule {
|
|
|
- .schedule-item {
|
|
|
- display: flex;
|
|
|
- align-items: flex-start;
|
|
|
- padding: 24rpx;
|
|
|
- background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
|
|
|
- border-radius: 16rpx;
|
|
|
- margin-bottom: 16rpx;
|
|
|
- border-left: 6rpx solid #667eea;
|
|
|
-
|
|
|
- &.tomorrow {
|
|
|
- border-left-color: #30cfd0;
|
|
|
- }
|
|
|
-
|
|
|
- .schedule-time {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- margin-right: 20rpx;
|
|
|
- min-width: 100rpx;
|
|
|
-
|
|
|
- .time-period {
|
|
|
- font-size: 22rpx;
|
|
|
- color: #999999;
|
|
|
- margin-bottom: 4rpx;
|
|
|
- }
|
|
|
-
|
|
|
- .time-value {
|
|
|
- font-size: 28rpx;
|
|
|
- font-weight: 600;
|
|
|
- color: #333333;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .schedule-content {
|
|
|
- flex: 1;
|
|
|
+ .resetButton {
|
|
|
+ background-color: transparent !important;
|
|
|
+ border: none !important;
|
|
|
+ display: inline !important;
|
|
|
|
|
|
- .schedule-title {
|
|
|
- font-size: 28rpx;
|
|
|
- color: #333333;
|
|
|
- line-height: 1.5;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ &::after {
|
|
|
+ border: none !important;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- .bottom-spacer {
|
|
|
- height: 40rpx;
|
|
|
}
|
|
|
</style>
|