Files
lucky_shop/pages_tool/card/style.vue

662 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="cs-page">
<!-- 顶部段控: 名片模板 / 分享封面 -->
<view class="cs-seg">
<view class="cs-seg-item" :class="{ active: seg === 'tpl' }" @tap="switchSeg('tpl')">名片模板</view>
<view class="cs-seg-item" :class="{ active: seg === 'cover' }" @tap="switchSeg('cover')">分享封面</view>
</view>
<!-- ============ 名片模板 ============ -->
<block v-if="seg === 'tpl'">
<!-- 名片预览: 姓名/资料内容一律保持原样, 只改布局与配色
- 卡面底色跟随「选择背景」
- 选中的模板决定版式(pv-classic = 第一个模板, 参考图的纸感居中版) -->
<view class="cs-preview" :class="'pv-' + previewTplType" :style="previewStyle">
<!-- 特种纸肌理层: 真实可平铺纤维纹理图(参考图同款棉絮纸), 置于文字之下 -->
<image v-if="previewBgTexture" class="cs-preview-texture" :src="paperTexture" />
<text class="cs-name">{{ card.name }}</text>
<text class="cs-job">{{ card.job_title }}</text>
<text class="cs-company">{{ card.company }}</text>
<view class="cs-divider"></view>
<view class="cs-row" v-if="card.mobile">
<text class="cs-row-icon iconfont icon-dianhua"></text>
<text class="cs-row-text">{{ card.mobile }}</text>
</view>
<view class="cs-row" v-if="card.email">
<text class="cs-row-icon">@</text>
<text class="cs-row-text">{{ card.email }}</text>
</view>
<view class="cs-row" v-if="card.address">
<text class="cs-row-icon iconfont icon-dizhi"></text>
<text class="cs-row-text">{{ card.address }}</text>
</view>
</view>
<!-- 解锁更多 -->
<view class="cs-unlock" @tap="onUnlock">
<text class="cs-unlock-icon iconfont icon-huiyuan"></text>
<text class="cs-unlock-text">解锁更多新模板、个性化logo,自由排版</text>
<text class="cs-unlock-arrow iconfont icon-right"></text>
</view>
<!-- 选择模板 -->
<view class="cs-section">
<text class="cs-title">选择模板</text>
<scroll-view scroll-x class="cs-scroll">
<view class="cs-thumbs">
<view v-for="tpl in templates" :key="tpl.id" class="cs-thumb"
:class="'tpl-' + tpl.type" @tap="selectTpl(tpl.id)">
<view class="tpl-inner">
<view class="tpl-bar w70"></view>
<view class="tpl-bar w45"></view>
<view class="tpl-bar w55"></view>
</view>
<view v-if="selectedTpl === tpl.id" class="cs-check">
<view class="cs-check-mark"></view>
</view>
</view>
</view>
</scroll-view>
</view>
<!-- 选择背景 -->
<view class="cs-section">
<text class="cs-title">选择背景</text>
<scroll-view scroll-x class="cs-scroll">
<view class="cs-thumbs">
<view v-for="bg in backgrounds" :key="bg.id" class="cs-thumb"
:style="bgStyle(bg)"
@tap="selectBg(bg.id)">
<image v-if="bg.texture" class="cs-thumb-texture" :src="paperTexture" />
<view v-if="selectedBg === bg.id" class="cs-check">
<view class="cs-check-mark"></view>
</view>
</view>
</view>
</scroll-view>
</view>
</block>
<!-- ============ 分享封面 ============ -->
<block v-else>
<view class="cs-cover-preview">
<view class="cs-cover-inner">
<text class="cs-cover-name">{{ card.name }}</text>
<text class="cs-cover-job">{{ card.job_title }}</text>
<text class="cs-cover-company">{{ card.company }}</text>
</view>
</view>
<view class="cs-section">
<text class="cs-title">选择封面</text>
<scroll-view scroll-x class="cs-scroll">
<view class="cs-thumbs">
<view v-for="cover in covers" :key="cover.id" class="cs-thumb"
:style="'background-color:' + cover.color" @tap="selectCover(cover.id)">
<view v-if="selectedCover === cover.id" class="cs-check">
<view class="cs-check-mark"></view>
</view>
</view>
</view>
</scroll-view>
</view>
</block>
<!-- 底部保存 -->
<view class="cs-footer">
<view class="cs-save" @tap="onSave">保存</view>
</view>
</view>
</template>
<script>
// 名片样式: 本页只改样式(模板/背景), 名片资料一律取 card/detail 的真实数据回填, 不做任何改动。
// 「保存」待后端提供样式保存端点后再接入(card/style/save 之类)。
export default {
data() {
return {
seg: 'tpl',
cardId: '',
// 特种纸肌理图(可平铺棉絮纸纹理, scripts/gen-paper-texture.js 生成)
paperTexture: '/static/images/paper-fiber.png',
// 名片资料(真实数据, 由 loadCard 回填)
card: {
name: '',
job_title: '',
company: '',
mobile: '',
email: '',
address: ''
},
// 模板缩略图示意: type 决定缩略图配色(classic = 参考图的纸感米色块)
templates: [
{ id: 't1', type: 'classic' },
{ id: 't2', type: 'photo' },
{ id: 't3', type: 'lines' },
{ id: 't4', type: 'dark' },
{ id: 't5', type: 'navy' }
],
// 默认选中第一个(参考图)
selectedTpl: 't1',
backgrounds: [
// 第一个背景 = 参考图样式: 暖调奶油本白的特种纸(棉絮纸/肌理纸),
// texture: true 时叠加云絮状纤维斑纹(无规则网点), 选中后改变卡面底色
{ id: 'b1', color: '#F3EFE7', texture: true },
{ id: 'b2', color: '#c9ced6' },
{ id: 'b3', color: '#243b5e' },
{ id: 'b4', color: '#8b95a3' },
{ id: 'b5', color: '#ffffff', border: '#2aa5ff' }
],
selectedBg: 'b1',
covers: [
{ id: 'c1', color: '#5a6473' },
{ id: 'c2', color: '#c9ced6' },
{ id: 'c3', color: '#243b5e' },
{ id: 'c4', color: '#8b95a3' },
{ id: 'c5', color: '#ffffff' }
],
selectedCover: 'c1'
};
},
onLoad(options) {
this.cardId = decodeURIComponent(options.card_id || '');
this.loadCard();
},
computed: {
// 卡面底色跟随「选择背景」; 姓名/资料内容始终原样, 不随模板改变
previewStyle() {
const bg = this.backgrounds.find(item => item.id === this.selectedBg);
return bg ? this.bgStyle(bg) : '';
},
// 当前选中模板的类型(classic/photo/lines/dark/navy), 决定预览的版式类 pv-*
previewTplType() {
const tpl = this.templates.find(item => item.id === this.selectedTpl);
return tpl ? tpl.type : 'classic';
},
// 选中背景是否带特种纸肌理(叠加 paper-fiber 纹理图)
previewBgTexture() {
const bg = this.backgrounds.find(item => item.id === this.selectedBg);
return !!(bg && bg.texture);
}
},
methods: {
// 拉取名片真实资料回填预览(只读展示, 本页不改资料)
loadCard() {
if (!this.cardId) return;
this.$cardApi.cardDetail({
data: { card_id: this.cardId },
success: res => {
if (res.code == 0 && res.data && res.data.relation) {
this.card = this.pickCard(res.data.relation);
}
},
fail: () => {
uni.showToast({ title: '名片资料加载失败', icon: 'none' });
}
});
},
// relation → 预览字段(口径与详情页 fieldRows 一致)
pickCard(r) {
return {
name: r.name || '',
job_title: r.job_title || '',
company: r.company || '',
mobile: r.mobile || r.phone || '',
email: r.email || '',
address: [r.country, r.province, r.city, r.address].filter(Boolean).join(' ')
};
},
switchSeg(value) {
if (this.seg === value) return;
this.seg = value;
},
selectTpl(id) {
this.selectedTpl = id;
},
selectBg(id) {
this.selectedBg = id;
},
/**
* 背景色块/预览卡共用的内联样式(只管底色与描边)。
* texture: true 的肌理由 paper-fiber 纹理图以 <image> 层叠加(见模板),
* 不再用 CSS 渐变模拟 —— 真实纤维纹理才能和参考图一致。
*/
bgStyle(bg) {
if (!bg) return '';
let style = 'background-color:' + bg.color + ';';
if (bg.border) {
style += 'border:2rpx solid ' + bg.border + ';';
}
return style;
},
selectCover(id) {
this.selectedCover = id;
},
onUnlock() {
uni.showToast({ title: '解锁更多模板(接口待接入)', icon: 'none' });
},
onSave() {
// 接口待接入: 先给反馈, 保证交互可验证
uni.showToast({ title: '已保存(接口待接入)', icon: 'none' });
}
}
};
</script>
<style lang="scss" scoped>
.cs-page {
min-height: 100vh;
background-color: #f6f7f9;
// 底部给固定保存条留位
padding: 0 24rpx 200rpx;
box-sizing: border-box;
}
// 段控: 灰底轨道 + 白色选中胶囊
.cs-seg {
display: flex;
margin-top: 20rpx;
padding: 6rpx;
background-color: #eceef1;
border-radius: 16rpx;
.cs-seg-item {
flex: 1;
height: 68rpx;
line-height: 68rpx;
text-align: center;
font-size: 28rpx;
color: #8a94a6;
border-radius: 12rpx;
&.active {
background-color: #ffffff;
color: #333333;
font-weight: 600;
}
}
}
// 名片预览: 白底 + 蓝色粗描边(姓名/资料原样, 仅底色可被背景覆盖)
.cs-preview {
position: relative;
margin-top: 24rpx;
padding: 32rpx 28rpx;
background-color: #ffffff;
border: 6rpx solid #2aa5ff;
border-radius: 12rpx;
box-sizing: border-box;
// 特种纸肌理层: 铺满卡面, 压在底色上、文字下(后续兄弟节点设 relative 保证盖在纹理上)
.cs-preview-texture {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border-radius: 12rpx;
}
> .cs-name,
> .cs-job,
> .cs-company,
> .cs-divider,
> .cs-row {
position: relative;
}
.cs-name {
display: block;
font-size: 44rpx;
font-weight: 600;
color: #333333;
line-height: 1.2;
}
.cs-job {
display: block;
margin-top: 12rpx;
font-size: 26rpx;
color: #555555;
}
.cs-company {
display: block;
margin-top: 6rpx;
font-size: 26rpx;
color: #555555;
}
.cs-divider {
height: 2rpx;
margin: 26rpx 0;
background-color: #eef0f3;
}
.cs-row {
display: flex;
align-items: center;
& + .cs-row {
margin-top: 14rpx;
}
}
.cs-row-icon {
width: 34rpx;
flex-shrink: 0;
margin-right: 12rpx;
font-size: 26rpx;
line-height: 1.2;
color: #4a5568;
text-align: center;
}
.cs-row-text {
flex: 1;
min-width: 0;
font-size: 26rpx;
color: #555555;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
// ===== 第一个模板「纸感版」(参考图) =====
// 只改版式与配色: 资料内容(姓名/职位/公司/手机号...)一律原样
// 参考图配色: 分割线及以上 = 古铜金; 分割线以下 = 暖灰褐
&.pv-classic {
// 参考图是无描边的纸卡, 只用柔和投影; 保留边框宽度避免尺寸跳动
border-color: transparent;
box-shadow: 0 8rpx 24rpx rgba(122, 104, 78, 0.16);
// 版式: 资料全部居中
.cs-name,
.cs-job,
.cs-company,
.cs-row-text {
text-align: center;
}
// 分割线以上: 姓名最大最粗, 职位/公司同色次之
.cs-name {
font-size: 42rpx;
font-weight: 700;
color: #b5813c;
}
.cs-job {
margin-top: 14rpx;
font-size: 26rpx;
font-weight: 600;
color: #b5813c;
}
.cs-company {
margin-top: 4rpx;
font-size: 26rpx;
font-weight: 600;
color: #b5813c;
}
// 分割线: 参考图是一条很淡的浅茶色细线
.cs-divider {
margin: 5rpx 0;
background-color: rgba(181, 129, 60, 0.3);
}
// 分割线以下: 居中纯文字(参考图无行首图标), 暖灰褐色, 间距紧凑
.cs-row {
justify-content: center;
& + .cs-row {
margin-top: -10rpx;
}
.cs-row-icon {
display: none;
}
.cs-row-text {
flex: none;
font-size: 30rpx;
color: #000000;
}
}
}
}
// 解锁更多新模板横幅
.cs-unlock {
display: flex;
align-items: center;
margin-top: 24rpx;
padding: 24rpx;
background-color: #eaf4ff;
border-radius: 12rpx;
.cs-unlock-icon {
flex-shrink: 0;
margin-right: 14rpx;
font-size: 32rpx;
color: #2aa5ff;
}
.cs-unlock-text {
flex: 1;
min-width: 0;
font-size: 24rpx;
color: #333333;
}
.cs-unlock-arrow {
flex-shrink: 0;
margin-left: 10rpx;
font-size: 26rpx;
color: #9aa4b0;
}
}
// 分区标题 + 横向滚动缩略图
.cs-section {
margin-top: 32rpx;
.cs-title {
display: block;
margin-bottom: 20rpx;
font-size: 28rpx;
font-weight: 600;
color: #333333;
}
}
.cs-scroll {
white-space: nowrap;
.cs-thumbs {
display: inline-flex;
}
}
.cs-thumb {
position: relative;
width: 152rpx;
height: 100rpx;
flex-shrink: 0;
margin-right: 20rpx;
border-radius: 10rpx;
box-sizing: border-box;
overflow: hidden;
background-color: #ffffff;
border: 2rpx solid #e8ebee;
// 特种纸肌理层: 铺满色块, 选中角标(.cs-check)在 DOM 之后仍盖在其上
.cs-thumb-texture {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
// 模板内部线条示意
.tpl-inner {
padding: 18rpx 16rpx;
.tpl-bar {
height: 8rpx;
border-radius: 4rpx;
background-color: #dfe3e8;
& + .tpl-bar {
margin-top: 10rpx;
}
}
.w70 {
width: 70%;
}
.w45 {
width: 45%;
}
.w55 {
width: 55%;
}
}
// 深色模板示意
&.tpl-dark,
&.tpl-navy {
border-color: transparent;
.tpl-bar {
background-color: rgba(255, 255, 255, 0.45);
}
}
&.tpl-dark {
background-color: #4a5260;
}
&.tpl-navy {
background-color: #1f2a44;
}
// 模板一(参考图): 纸感米色纯色块
&.tpl-classic {
border-color: transparent;
background-color: #ece5db;
.tpl-inner {
display: none;
}
}
// 带人像的模板示意
&.tpl-photo {
.tpl-inner {
padding: 0;
.tpl-bar {
display: none;
}
}
&::after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 56rpx;
height: 100%;
background-color: #6b7280;
}
}
}
// 选中角标(参考图): 白底蓝勾圆, 居中压在缩略图上
.cs-check {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 34rpx;
height: 34rpx;
border-radius: 50%;
background-color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
.cs-check-mark {
width: 14rpx;
height: 7rpx;
margin-top: -4rpx;
border-left: 3rpx solid #2aa5ff;
border-bottom: 3rpx solid #2aa5ff;
transform: rotate(-45deg);
}
}
// 分享封面预览
.cs-cover-preview {
margin-top: 24rpx;
padding: 32rpx;
height: 320rpx;
background-color: #ffffff;
border: 6rpx solid #2aa5ff;
border-radius: 12rpx;
box-sizing: border-box;
.cs-cover-inner {
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
}
.cs-cover-name {
font-size: 40rpx;
font-weight: 600;
color: #333333;
}
.cs-cover-job {
margin-top: 10rpx;
font-size: 26rpx;
color: #555555;
}
.cs-cover-company {
margin-top: 6rpx;
font-size: 26rpx;
color: #555555;
}
}
// 底部固定保存条
.cs-footer {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 20rpx 24rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
background-color: #ffffff;
.cs-save {
height: 88rpx;
line-height: 88rpx;
text-align: center;
border-radius: 44rpx;
background-color: #2aa5ff;
color: #ffffff;
font-size: 32rpx;
}
}
</style>