chore:名片样式和后端同步
This commit is contained in:
@@ -1514,6 +1514,13 @@
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "card/views",
|
||||
"style": {
|
||||
"navigationBarTitleText": "谁看了我",
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "card/contact-edit",
|
||||
"style": {
|
||||
|
||||
@@ -35,11 +35,11 @@
|
||||
<text>编辑资料</text>
|
||||
</view>
|
||||
<view class="ca-divider"></view>
|
||||
<view class="ca-item" @tap="onStyleTap">
|
||||
<view class="ca-item" @tap="onStyleTap" v-if="designEnabled">
|
||||
<text class="ca-icon iconfont icon-erweima"></text>
|
||||
<text>名片样式</text>
|
||||
</view>
|
||||
<view class="ca-divider"></view>
|
||||
<view class="ca-divider" v-if="designEnabled"></view>
|
||||
<view class="ca-item" @tap="goList">
|
||||
<text class="ca-icon iconfont icon-shuaxin"></text>
|
||||
<text>切换名片</text>
|
||||
@@ -213,7 +213,9 @@ export default {
|
||||
qrUrl: '',
|
||||
// 交换名片: 待处理请求(真实, exchange/lists, 只含 status=0)
|
||||
exchangeList: [],
|
||||
exchangeCount: 0
|
||||
exchangeCount: 0,
|
||||
// 商家是否开启「员工端样式自选」(GET design/presets 的 enabled); 默认 true(失败开放)
|
||||
designEnabled: true
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -345,12 +347,14 @@ export default {
|
||||
this.cardId = decodeURIComponent(options.card_id || '');
|
||||
this.loadDetail();
|
||||
this.loadExchange();
|
||||
this.loadDesignEnabled();
|
||||
},
|
||||
onShow() {
|
||||
// 首次进入由 onLoad 负责加载; 从编辑页返回时(onShow 再次触发)刷新
|
||||
if (this._loadedOnce) {
|
||||
this.loadDetail();
|
||||
this.loadExchange();
|
||||
this.loadDesignEnabled();
|
||||
}
|
||||
this._loadedOnce = true;
|
||||
},
|
||||
@@ -558,6 +562,16 @@ export default {
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
// 查询商家是否开启「员工端样式自选」(控制名片样式入口显隐)
|
||||
loadDesignEnabled() {
|
||||
this.$cardApi.cardDesignPresets({
|
||||
success: res => {
|
||||
const d = res.data || {};
|
||||
if (res.code == 0) this.designEnabled = d.enabled !== false;
|
||||
},
|
||||
fail: () => {} // 失败开放(默认 true, 入口保留)
|
||||
});
|
||||
},
|
||||
// 「名片样式」: 进入样式选择页(名片模板 / 分享封面)
|
||||
onStyleTap() {
|
||||
const url = this.cardId
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
</view>
|
||||
<view class="claim-btn create-btn" @tap="goCreate">新建</view>
|
||||
<view class="claim-btn" @tap="onClaimTap">认领</view>
|
||||
<view class="claim-btn" @tap="goViews">访客</view>
|
||||
</view>
|
||||
|
||||
<!-- 筛选条: 仅看收藏 -->
|
||||
@@ -20,6 +21,13 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 筛选条: 跟进(全部 / 待跟进 / 已完成, follow_up 传 due/done) -->
|
||||
<view class="filter-row">
|
||||
<view class="fav-filter" :class="{ active: followTab === 'all' }" @tap="switchFollow('all')">全部</view>
|
||||
<view class="fav-filter" :class="{ active: followTab === 'due' }" @tap="switchFollow('due')">待跟进</view>
|
||||
<view class="fav-filter" :class="{ active: followTab === 'done' }" @tap="switchFollow('done')">已完成</view>
|
||||
</view>
|
||||
|
||||
<!-- 列表 -->
|
||||
<view class="card-list">
|
||||
<view v-for="(item, index) in list" :key="item.id || index" class="card-item"
|
||||
@@ -33,10 +41,18 @@
|
||||
{{ [item.job_title, item.company].filter(Boolean).join(' · ') }}
|
||||
</view>
|
||||
<view class="card-mobile" v-if="item.mobile">📱 {{ item.mobile }}</view>
|
||||
<view class="card-follow" v-if="item.follow_up_done == 1">
|
||||
<text class="card-follow-done">✓ 已完成</text>
|
||||
</view>
|
||||
<view class="card-follow" v-else-if="followTab === 'due'">
|
||||
<text class="card-follow-due">跟进中</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 收藏星标: 实心=已收藏, 空心=未收藏; 单独点击不进详情 -->
|
||||
<text class="card-fav" :class="{ 'is-fav': item.is_favorite == 1 }"
|
||||
@tap.stop="toggleFavorite(item)">{{ item.is_favorite == 1 ? '★' : '☆' }}</text>
|
||||
<view v-if="followTab === 'due' && item.follow_up_done != 1" class="card-done-btn"
|
||||
@tap.stop="markDone(item)">完成</view>
|
||||
<view class="card-arrow">›</view>
|
||||
</view>
|
||||
|
||||
@@ -47,9 +63,34 @@
|
||||
<text v-else class="load-end">— 没有更多了 —</text>
|
||||
</view>
|
||||
|
||||
<!-- 空态 -->
|
||||
<ns-empty v-if="!isLoading && list.length === 0" :isIndex="false"
|
||||
:text="emptyText"></ns-empty>
|
||||
<!-- 空态: 建卡申请 / 申请状态(2.11.15) -->
|
||||
<view v-if="!isLoading && list.length === 0" class="card-empty">
|
||||
<block v-if="apply && apply.status === 0">
|
||||
<view class="empty-icon">⏳</view>
|
||||
<view class="empty-title">申请审核中</view>
|
||||
<view class="empty-sub">您的建卡申请正在等待商家审批</view>
|
||||
</block>
|
||||
<block v-else-if="apply && apply.status === 1">
|
||||
<view class="empty-icon">✅</view>
|
||||
<view class="empty-title">已通过</view>
|
||||
<view class="empty-sub">下拉刷新查看我的名片</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<view class="empty-icon">📇</view>
|
||||
<view class="empty-title" v-if="apply && apply.status === 2">已拒绝:{{ apply.note || '商家未填写理由' }}</view>
|
||||
<view class="empty-title" v-else>还没有名片</view>
|
||||
<view class="empty-sub">提交信息,申请商家为您建卡</view>
|
||||
<view class="apply-form">
|
||||
<input class="apply-input" :value="applyName" @input="e => applyName = e.detail.value"
|
||||
placeholder="您的姓名" />
|
||||
<input class="apply-input" :value="applyMobile" @input="e => applyMobile = e.detail.value"
|
||||
placeholder="手机号" type="number" />
|
||||
<view class="apply-submit" :class="{ disabled: applying }" @tap="submitApply">
|
||||
{{ applying ? '提交中…' : '提交申请' }}
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 认领弹层: 支持领取码/名片编号 + 扫码带参预填(与 card_claim_api 文档同步) -->
|
||||
@@ -96,7 +137,14 @@ export default {
|
||||
showClaim: false,
|
||||
claimInput: '',
|
||||
claimMode: 'code', // code=领取码(主通道), id=名片编号(旧入口兼容)
|
||||
pendingClaimCode: '' // 扫码带参预填的码
|
||||
pendingClaimCode: '', // 扫码带参预填的码
|
||||
// 跟进筛选(2.11.3): all / due(待跟进) / done(已完成)
|
||||
followTab: 'all',
|
||||
// 建卡申请状态(2.11.15)
|
||||
apply: null, // { status, status_text, note, has_card }
|
||||
applyName: '',
|
||||
applyMobile: '',
|
||||
applying: false
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
@@ -135,6 +183,68 @@ export default {
|
||||
this.onlyFav = !this.onlyFav;
|
||||
this.refresh();
|
||||
},
|
||||
// 跟进筛选切换(全部/待跟进/已完成, 2.11.3)
|
||||
switchFollow(tab) {
|
||||
this.followTab = tab;
|
||||
this.refresh();
|
||||
},
|
||||
// 标记跟进完成(2.11.3): followDone, 成功后该卡从待跟进消失
|
||||
markDone(item) {
|
||||
const cardId = this.cardIdOf(item);
|
||||
if (!cardId) return;
|
||||
uni.showLoading({ title: '标记中…' });
|
||||
this.$cardApi.cardFollowDone({
|
||||
data: { card_id: cardId },
|
||||
success: res => {
|
||||
uni.hideLoading();
|
||||
if (res.code == 0) {
|
||||
uni.showToast({ title: '已标记完成', icon: 'success' });
|
||||
this.refresh();
|
||||
} else {
|
||||
this.handleApiError(res);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
|
||||
}
|
||||
});
|
||||
},
|
||||
// 空态: 查询我的建卡申请状态(2.11.15)
|
||||
loadApplyStatus() {
|
||||
this.$cardApi.applyStatus({
|
||||
success: res => {
|
||||
if (res.code == 0) this.apply = res.data || null;
|
||||
},
|
||||
fail: () => {}
|
||||
});
|
||||
},
|
||||
// 提交建卡申请(2.11.15)
|
||||
submitApply() {
|
||||
const name = (this.applyName || '').trim();
|
||||
const mobile = (this.applyMobile || '').trim();
|
||||
if (!name) { uni.showToast({ title: '请输入姓名', icon: 'none' }); return; }
|
||||
if (!mobile) { uni.showToast({ title: '请输入手机号', icon: 'none' }); return; }
|
||||
this.applying = true;
|
||||
this.$cardApi.applySubmit({
|
||||
data: { name: name, mobile: mobile },
|
||||
success: res => {
|
||||
this.applying = false;
|
||||
if (res.code == 0) {
|
||||
uni.showToast({ title: '已提交,等待审核', icon: 'none' });
|
||||
this.apply = { status: 0, status_text: '待审核' };
|
||||
this.applyName = '';
|
||||
this.applyMobile = '';
|
||||
} else {
|
||||
this.handleApiError(res);
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
this.applying = false;
|
||||
uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 切换收藏(双向 toggle): 直接调, 用返回的 is_favorite 回填。
|
||||
* 乐观更新 + 失败回滚; 仅看收藏模式下取消收藏则从列表移除该行。
|
||||
@@ -187,6 +297,8 @@ export default {
|
||||
keyword: this.keyword.trim()
|
||||
};
|
||||
if (this.onlyFav) reqData.favorite = 1;
|
||||
if (this.followTab === 'due') reqData.follow_up = 'due';
|
||||
else if (this.followTab === 'done') reqData.follow_up = 'done';
|
||||
this.$cardApi.cardLists({
|
||||
data: reqData,
|
||||
success: res => {
|
||||
@@ -197,6 +309,8 @@ export default {
|
||||
this.count = data.count || 0;
|
||||
this.page = pageNo;
|
||||
this.list = pageNo === 1 ? rows : this.list.concat(rows);
|
||||
// 空态(首页无卡): 拉取建卡申请状态, 驱动空态申请 UI(2.11.15)
|
||||
if (pageNo === 1 && rows.length === 0) this.loadApplyStatus();
|
||||
this.emptyText = this.keyword.trim()
|
||||
? '未找到匹配的名片'
|
||||
: '暂无名片,可点击右上角「新建」或「认领」添加';
|
||||
@@ -242,6 +356,12 @@ export default {
|
||||
url: '/pages_tool/card/edit'
|
||||
});
|
||||
},
|
||||
// 访客轨迹(2.11.4): 进入「谁看了我」总入口(不带 card_id)
|
||||
goViews() {
|
||||
uni.navigateTo({
|
||||
url: '/pages_tool/card/views'
|
||||
});
|
||||
},
|
||||
// 认领: 打开弹层(支持领取码/名片编号 + 扫码带参预填, 与 card_claim_api 文档同步)
|
||||
onClaimTap() {
|
||||
this.claimInput = this.pendingClaimCode || '';
|
||||
@@ -521,6 +641,85 @@ export default {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 列表行: 跟进徽标 + 完成按钮 */
|
||||
.card-follow {
|
||||
margin-top: 8rpx;
|
||||
|
||||
.card-follow-done {
|
||||
font-size: 22rpx;
|
||||
color: #1aad19;
|
||||
}
|
||||
|
||||
.card-follow-due {
|
||||
font-size: 22rpx;
|
||||
color: #f5a623;
|
||||
}
|
||||
}
|
||||
|
||||
.card-done-btn {
|
||||
flex-shrink: 0;
|
||||
margin-left: 16rpx;
|
||||
padding: 8rpx 20rpx;
|
||||
background-color: var(--main-color, #0054a5);
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
border-radius: 24rpx;
|
||||
}
|
||||
|
||||
/* 空态: 建卡申请 */
|
||||
.card-empty {
|
||||
text-align: center;
|
||||
padding: 120rpx 48rpx;
|
||||
|
||||
.empty-icon {
|
||||
font-size: 96rpx;
|
||||
}
|
||||
|
||||
.empty-title {
|
||||
margin-top: 24rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.empty-sub {
|
||||
margin-top: 12rpx;
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.apply-form {
|
||||
margin-top: 48rpx;
|
||||
|
||||
.apply-input {
|
||||
height: 84rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 14rpx;
|
||||
padding: 0 24rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 24rpx;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.apply-submit {
|
||||
height: 88rpx;
|
||||
border-radius: 999rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, #2aa5ff 0%, #0d7bf0 100%);
|
||||
color: #fff;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 认领弹层(与 card_claim_api 文档同步) */
|
||||
.claim-mask {
|
||||
position: fixed;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -46,6 +46,8 @@ const DOC_URLS = [
|
||||
'/card/api/card/recognize',
|
||||
'/card/api/card/retry',
|
||||
'/card/api/card/recognizeBatch',
|
||||
'/card/api/card/followDone', // 跟进完成态 2.11.3
|
||||
'/card/api/card/views', // 访客轨迹 2.11.4
|
||||
// 人脉库 /card/api/contact/*
|
||||
'/card/api/contact/lists',
|
||||
'/card/api/contact/add',
|
||||
@@ -59,7 +61,11 @@ const DOC_URLS = [
|
||||
// 交换名片 /card/api/exchange/*
|
||||
'/card/api/exchange/lists',
|
||||
'/card/api/exchange/agree',
|
||||
'/card/api/exchange/ignore'
|
||||
'/card/api/exchange/ignore',
|
||||
'/card/api/apply/submit', // 员工建卡申请 2.11.15
|
||||
'/card/api/apply/status', // 员工建卡申请 2.11.15
|
||||
'/card/api/design/presets', // 名片预设列表(同源后台 CardTemplatePresets, 后端 v2 无 /card/ 段)
|
||||
'/card/api/design/save' // 应用预设/保存本卡样式
|
||||
];
|
||||
|
||||
// helper 方法名 ↔ URL 常量名(收口层必须两端齐全)
|
||||
@@ -82,11 +88,17 @@ const HELPER_URL_PAIRS = [
|
||||
['leadSetStatus', 'LEAD_SET_STATUS'],
|
||||
['exchangeLists', 'EXCHANGE_LISTS'],
|
||||
['exchangeAgree', 'EXCHANGE_AGREE'],
|
||||
['exchangeIgnore', 'EXCHANGE_IGNORE']
|
||||
['exchangeIgnore', 'EXCHANGE_IGNORE'],
|
||||
['cardFollowDone', 'CARD_FOLLOW_DONE'],
|
||||
['cardViews', 'CARD_VIEWS'],
|
||||
['applySubmit', 'APPLY_SUBMIT'],
|
||||
['applyStatus', 'APPLY_STATUS'],
|
||||
['cardDesignPresets', 'CARD_DESIGN_PRESETS'],
|
||||
['cardDesignSave', 'CARD_DESIGN_SAVE']
|
||||
];
|
||||
|
||||
// 文档 3.3/4.2/4.4/3.7: 嵌套对象/数组入参必须走 JSON body(sendJson)
|
||||
const JSON_BODY_HELPERS = ['cardUpdate', 'cardCreate', 'contactAdd', 'contactUpdate', 'cardRecognizeBatch', 'exchangeAgree', 'exchangeIgnore'];
|
||||
const JSON_BODY_HELPERS = ['cardUpdate', 'cardCreate', 'contactAdd', 'contactUpdate', 'cardRecognizeBatch', 'exchangeAgree', 'exchangeIgnore', 'cardDesignSave'];
|
||||
|
||||
// =============================================================
|
||||
// 1. 端点与后端文档逐一比对
|
||||
|
||||
Reference in New Issue
Block a user