增加产品库

This commit is contained in:
chenbin 2026-10-23 12:10:26 +08:00
parent 825f69d886
commit 2b02e3a65b
5 changed files with 561 additions and 2 deletions

176
src/api/prod.js Normal file
View File

@ -0,0 +1,176 @@
// 友福同享智能健康项目 · 数据(来源:友福同享项目--智能健康2026.10.22.xlsx)
// 价格单位:元
export const PROJECTS = [
{
id: 1, name: '23天减重版', price: 3980, audience: '肥胖人群',
role: '教练', roleCount: 1, nutrient: '有', band: '有', course: '无',
note: '', stage: '存量',
recommission: '合伙人:35%;直销:30%',
second: '渠道5%+推荐30%,合计:最高不超出35%',
r1: 0.3, r2: 0.05, rTotal: 0.35, r1Range: '30%', r2Range: '5%',
coachMain: 0, coachSub: 800, coachService: 0,
material: '营养素3种:友福蛋白粉、纤维粉、GNC营养包;智能设备:体脂秤、手环',
materialFee: 1000, materialRate: 0.2513, coachRate: 0.2010, profitRate: 0.1977,
service: [''],
hasIntro: true, hasBuy: true, link: '友福同享APP-用户端',
tag: '减重',
},
{
id: 2, name: '23天迷你版', price: 3980, audience: '亚健康人群',
role: '教练', roleCount: 1, nutrient: '有', band: '有', course: '无',
note: '', stage: '新增',
recommission: '合伙人:35%;直销:30%',
second: '渠道5%+推荐30%,合计:最高不超出35%',
r1: 0.3, r2: 0.05, rTotal: 0.35, r1Range: '30%', r2Range: '5%',
coachMain: 0, coachSub: 800, coachService: 0,
material: '营养素3种:友福蛋白粉、纤维粉、GNC营养包;智能设备:体脂秤、手环',
materialFee: 1000, materialRate: 0.2513, coachRate: 0.2010, profitRate: 0.1977,
service: [''], hasIntro: false, hasBuy: false, link: '', tag: '减重',
},
{
id: 3, name: '49天DMA服务包(2人套餐·夕阳红家庭版)',
sub: '子女家属服务2周 / 老人服务49天', price: 29800, audience: '亚健康人群',
role: '主、副教练、客服', roleCount: 3, nutrient: '有', band: '有', course: '无',
note: '1、夕阳红家庭版,2人做方案;\n2、子女:14天迷你版本1人,老人:49天老人1人;\n3、方案可同时启动;\n4、需要建2个用户服务群。',
stage: '新增',
recommission: '合伙人:35%;直销:20%',
second: '渠道5-10%+推荐30-35%,合计:最高不超出45%',
r1: 0.35, r2: 0.1, rTotal: 0.45, r1Range: '20-35%', r2Range: '5-10%',
coachMain: 1200, coachSub: 2200, coachService: 700,
material: '49天用户/老人按原DMA配置;14天用户/子女:营养素2种(蛋白粉、纤维粉)+ 体脂秤、手环',
materialFee: 4500, materialRate: 0.1510, coachRate: 0.1376, profitRate: 0.2614,
service: ['每天服务', '餐单系统生成、转发', '最少3次视频会议沟通'],
hasIntro: false, hasBuy: false, link: '', tag: '旗舰',
},
{
id: 4, name: '49天DMA服务包(个人)', price: 29800, audience: '亚健康人群',
role: '主、副教练、客服', roleCount: 3, nutrient: '有', band: '有', course: '无',
note: '折扣:\n1、2个同时成交,享受9折优惠;\n2、3个及3个以上成交,享受8折优惠。',
stage: '存量 · 核心旗舰',
recommission: '合伙人:35%;直销:20%',
second: '渠道5-10%+推荐20-35%,合计:最高不超出45%',
r1: 0.35, r2: 0.1, rTotal: 0.45, r1Range: '20-35%', r2Range: '5-10%',
coachMain: 1000, coachSub: 2000, coachService: 500,
material: '营养素按方案走,常规6-8种品类;智能设备:体脂秤、手环',
materialFee: 3500, materialRate: 0.1174, coachRate: 0.1174, profitRate: 0.3151,
service: ['每天服务', '餐单系统生成、转发', '最少3次视频会议沟通'],
hasIntro: true, hasBuy: true, link: '友福同享APP-用户端', tag: '旗舰',
},
{
id: 5, name: '49天DMA服务包(B端)', price: 19800, audience: '企业·亚健康人群',
role: '主、副教练', roleCount: 2, nutrient: '有', band: '有', course: '无',
note: '1、10个起成交;\n2、副教练包含原客服的工作。',
stage: '新增',
recommission: '合伙人:25%;直销:20%',
second: '渠道5-10%+推荐20-25%,合计:最高不超出35%',
r1: 0.25, r2: 0.1, rTotal: 0.35, r1Range: '20-25%', r2Range: '5-10%',
coachMain: 1000, coachSub: 2000, coachService: 0,
material: '营养素按方案走,常规6-8种品类;智能设备:体脂秤、手环',
materialFee: 3500, materialRate: 0.1768, coachRate: 0.1515, profitRate: 0.3217,
service: ['每天服务', '餐单系统生成、转发', '最少3次视频会议沟通'],
hasIntro: false, hasBuy: false, link: '', tag: 'B端',
},
{
id: 6, name: '49天DMA服务包(B端-专项·中风)', price: 19800, audience: '中风、肢体不协调人群',
role: '主、副教练', roleCount: 2, nutrient: '有', band: '有', course: '无',
note: '1、10个起成交;\n2、副教练包含原客服的工作。',
stage: '新增',
recommission: '合伙人:25%;直销:20%',
second: '渠道5-10%+推荐20-25%,合计:最高不超出35%',
r1: 0.25, r2: 0.1, rTotal: 0.35, r1Range: '20-25%', r2Range: '5-10%',
coachMain: 1000, coachSub: 2000, coachService: 0,
material: '营养素按方案走,常规6-8种品类;智能设备:体脂秤、手环',
materialFee: 3500, materialRate: 0.1768, coachRate: 0.1515, profitRate: 0.3217,
service: ['每天服务', '餐单系统生成、转发', '最少3次视频会议沟通'],
hasIntro: false, hasBuy: false, link: '', tag: 'B端',
},
{
id: 7, name: '30天DMA服务包(二次重置)', price: 1888, audience: '友福方案结束后的用户',
role: '教练', roleCount: 1, nutrient: '自购', band: '自购', course: '无',
note: '1、用户方案后半年及以后,想重新唤醒DMA;\n2、用户自购营养素;\n3、商城一键下单原方案营养包;\n4、可自选前期教练或系统重新分配。',
stage: '新增',
recommission: '合伙人:25%;直销:20%',
second: '渠道5%+推荐20%,合计:最高不超出25%',
r1: 0.2, r2: 0.05, rTotal: 0.25, r1Range: '', r2Range: '',
coachMain: 0, coachSub: 1000, coachService: 0,
material: '无',
materialFee: 0, materialRate: 0, coachRate: 0.5297, profitRate: 0.2203,
service: ['每天服务,监督上秤观察数据', '餐单每天人工发送', '视频面谈不少于2次'],
hasIntro: false, hasBuy: false, link: '', tag: '续费',
},
{
id: 8, name: '教练订阅月卡(陪伴)', price: 199, audience: '友福方案结束后的用户',
role: '教练', roleCount: 1, nutrient: '自购', band: '自购', course: '无',
note: '1、方案后陪伴服务月卡;\n2、用户自购营养素,商城一键下单原方案营养包;\n3、可自选教练;\n4、教练有营养素提成:友福品牌营养素(蛋白粉、纤维粉)20元/盒。',
stage: '新增',
recommission: '合伙人:25%;直销:20%',
second: '渠道5%+推荐20%,合计:最高不超出25%',
r1: 0.2, r2: 0.05, rTotal: 0.25, r1Range: '', r2Range: '',
coachMain: 0, coachSub: 100, coachService: 0,
material: '无(用户自购营养素,教练佣金20元/盒)',
materialFee: 0, materialRate: 0, coachRate: 0.5025, profitRate: 0.2475,
service: ['定期服务,监督上秤观察数据', '用户用餐恢复正常', '视频面谈不少于2次'],
hasIntro: false, hasBuy: false, link: '', tag: '陪伴',
},
{
id: 9, name: '教练订阅年卡(陪伴)', price: 1999, audience: '友福方案结束后的用户',
role: '教练', roleCount: 1, nutrient: '自购', band: '自购', course: '无',
note: '1、方案后陪伴服务年卡;\n2、用户自购营养素,商城一键下单原方案营养包;\n3、可自选教练;\n4、教练有营养素提成20元/盒;\n5、系统自动发送服务费,按月发送。',
stage: '新增',
recommission: '合伙人:25%;直销:20%',
second: '渠道5%+推荐20%,合计:最高不超出25%',
r1: 0.2, r2: 0.05, rTotal: 0.25, r1Range: '', r2Range: '',
coachMain: 0, coachSub: 1000, coachService: 0,
material: '无(用户自购营养素,教练佣金20元/盒)',
materialFee: 0, materialRate: 0, coachRate: 0.5003, profitRate: 0.2497,
service: ['定期服务,监督上秤观察数据', '用户用餐恢复正常', '视频面谈不少于2次/月'],
hasIntro: false, hasBuy: false, link: '', tag: '陪伴',
},
{
id: 10, name: '教练培训(用户)', price: 2980, audience: '友福方案结束后的用户',
role: '培训老师', roleCount: 1, nutrient: '', band: '', course: '三课程培训',
courseDetail: '1、友福同享《身心健康管理师》;\n2、医药教育协会《健康管理师》;\n3、友福系统培训。',
note: '1、需完成49天DMA方可进入培训;\n2、每月可报名;\n3、线上教案、复习大纲、视频教学;\n4、颁发双证;\n5、线上考试通过可成为友福健康教练储备人员。',
stage: '新增',
recommission: '合伙人:25%;直销:20%',
second: '渠道5%+推荐20%,合计:最高不超出25%',
r1: 0.2, r2: 0.05, rTotal: 0.25, r1Range: '', r2Range: '',
coachMain: 0, coachSub: 0, coachService: 0,
material: '无',
materialFee: 1600, materialRate: 0.5369, coachRate: 0, profitRate: 0.2131,
service: ['提供考前学习、考试温习复习大纲、考前提醒', '专属学习群,可自定时间申请考试'],
hasIntro: false, hasBuy: false, link: '', tag: '培训',
},
{
id: 11, name: '教练培训(社会人员+体验10天DMA)', price: 5980, audience: '有就业需求',
role: '教练、培训老师', roleCount: 2, nutrient: '有', band: '有', course: '三课程培训',
courseDetail: '1、友福同享《身心健康管理师》;\n2、医药教育协会《健康管理师》;\n3、友福系统培训。',
note: '1、需完成10天DMA方可进入培训;\n2、每月可报名;\n3、线上教案、复习大纲、视频教学;\n4、颁发双证;\n5、线上考试通过可成为友福健康教练储备人员。',
stage: '新增',
recommission: '合伙人:35%;直销:30%',
second: '渠道5%+推荐30%,合计:最高不超出35%',
r1: 0.3, r2: 0.05, rTotal: 0.35, r1Range: '30%', r2Range: '5%',
coachMain: 0, coachSub: 500, coachService: 0,
material: '营养素2种:友福蛋白粉、纤维粉;智能设备:体脂秤、手环',
materialFee: 2070, materialRate: 0.3462, coachRate: 0.0836, profitRate: 0.2202,
service: ['健康服务:教练每天陪伴、发餐单、2次视频会议(方案前/后)', '学习培训:考前学习、复习大纲、考前提醒', '专属学习群,可自定时间申请考试'],
hasIntro: false, hasBuy: false, link: '', tag: '培训',
},
]
export const CATEGORIES = [
{ label: '全部', value: 'all', icon: 'grid-view', ids: PROJECTS.map(p => p.id) },
{ label: '旗舰DMA', value: 'flagship', icon: 'chart-bubble', ids: [3, 4, 5, 6] },
{ label: '减重版', value: 'loss', icon: 'fire', ids: [1, 2] },
{ label: '陪伴订阅', value: 'sub', icon: 'heart', ids: [8, 9] },
{ label: '续费重置', value: 'renew', icon: 'refresh', ids: [7] },
{ label: '教练培训', value: 'train', icon: 'education', ids: [10, 11] },
]
// DMA 折扣定单推荐费计算(以49天DMA个人版29800为例)
export const DISCOUNT_TABLE = [
{ type: '原价', paidRate: 1, pay: 29800, discount: 0, feeRate: 0.35, fee: 10430, share: '', main: 1000, sub: 2000, service: 500, note: '成交1人,原价销售' },
{ type: '九折', paidRate: 0.9, pay: 26820, discount: 2980, feeRate: 0.35, fee: 8940, share: '各50%', main: 1000, sub: 2000, service: 500, note: '成交2人,可打9折销售' },
{ type: '八折', paidRate: 0.8, pay: 23840, discount: 5960, feeRate: 0.35, fee: 7450, share: '各50%', main: 1000, sub: 2000, service: 500, note: '成交3人及以上,可打8折销售' },
]

View File

@ -2,6 +2,8 @@ import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import UserListView from '../views/UserListView.vue'
import UserDetailView from '../views/UserDetailView.vue'
import ProdListView from '../views/ProdListView.vue'
import ProdDetailView from '../views/ProdDetailView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
@ -28,6 +30,16 @@ const router = createRouter({
path: '/user/:id',
name: 'user_detail',
component: UserDetailView
},
{
path: '/prod',
name: 'prod_list',
component: ProdListView
},
{
path: '/prod/:id',
name: 'prod_detail',
component: ProdDetailView
}
],
})

View File

@ -1,7 +1,8 @@
<script setup lang="ts">
import {ref} from 'vue'
const toolList = ref([
{title:'DMA 案例库', description: '展示 DMA 典型案例用户', name: 'user_list'}
{title:'DMA 案例库', description: '展示 DMA 典型案例用户', name: 'user_list'},
{title:'DMA 产品库', description: '展示 DMA 系列产品', name: 'prod_list'},
])
import {useRouter} from 'vue-router'
@ -21,7 +22,7 @@ const toPage = (page: string) => {
<div class="brand-title">友福同享</div>
</div>
<t-cell-group title="友福同享工具集">
<t-cell class="line-start line-end" theme='card' v-for="tool in toolList" :title="tool.title" :description="tool.description" arrow @click="toPage(tool.name)"></t-cell>
<t-cell :class="`line-start ${(index + 1 )== toolList.length ? 'line-end':'' }`"" theme='card' v-for="(tool,index) in toolList" :title="tool.title" :description="tool.description" arrow @click="toPage(tool.name)"></t-cell>
</t-cell-group>
<div class="empty-bar"></div>
</main>

View File

@ -0,0 +1,200 @@
<template>
<div class="page">
<div class="proj-line">
<div class="proj-name-line">
<t-cell :title="`${proj.name}`" style="border-top-left-radius:8px;border-top-right-radius:8px;">
<template #title>
<div style="color:#fff;">{{(idx+1)}} {{proj.name}}</div>
</template>
<template #note>
<div style="min-width: 60px;color:#fff;">¥ {{proj.price}}</div>
</template>
</t-cell>
<t-cell title="适用人群" class="proj-name" :note="`${proj.audience}`"></t-cell>
<t-cell v-if="proj.sub" :title="proj.sub"></t-cell>
<t-cell v-if="proj.note" >
<template #title>
<div class="proj-note">{{proj.note}}</div>
</template>
</t-cell>
</div>
<t-cell-group title="产品说明">
<t-cell :title="proj.material"></t-cell>
</t-cell-group>
<t-cell-group title="服务说明" v-if="proj.service">
<t-cell v-for="ser in proj.service" :title="ser || '暂无说明'"></t-cell>
</t-cell-group>
<t-cell-group title="分润说明">
<t-cell :title="proj.recommission"></t-cell>
<t-cell :title="proj.second"></t-cell>
</t-cell-group>
<t-cell-group title="服务人员费用说明" v-if="proj.roleCount > 1">
<t-cell title="主教练" v-if="proj.coachMain > 0" :note="proj.coachMain + ''"></t-cell>
<t-cell title="副教练" v-if="proj.coachSub > 0" :note="proj.coachSub + ''"></t-cell>
<t-cell title="客服" v-if="proj.coachService > 0" style="border-radius:8px;" :note="proj.coachService + ''"></t-cell>
</t-cell-group>
<t-cell-group title="介绍人费用说明" >
<t-cell title="客户签订协议后 3 天内发放" style="border-radius:8px;" ></t-cell>
</t-cell-group>
<t-cell-group title="服务人员费用说明" v-if="proj.roleCount == 1">
<t-cell title="服务周期完成后 3 天内发放" style="border-radius:8px;" ></t-cell>
<t-cell title="教练" v-if="proj.coachMain > 0" style="border-radius:8px;" :note="proj.coachMain + ''"></t-cell>
<t-cell title="教练" v-if="proj.coachSub > 0" style="border-radius:8px;" :note="proj.coachSub + ''"></t-cell>
<t-cell title="教练" v-if="proj.coachService > 0" style="border-radius:8px;" :note="proj.coachService + ''"></t-cell>
</t-cell-group>
</div>
</div>
<div class="empty-bar"></div>
<div class="empty-bar"></div>
</template>
<script lang="ts" setup>
import { Icon as TIcon } from 'tdesign-icons-vue-next';
import { ref, onMounted } from 'vue';
import {useRoute, useRouter} from 'vue-router'
import {PROJECTS, DISCOUNT_TABLE} from '../api/prod'
const router = useRouter()
const route = useRoute()
const search = ref([])
const projID = ref(0)
const proj = ref({})
onMounted(() =>{
console.log('route', route)
console.log('router', router)
const id = route.params.id
projID.value = id
PROJECTS.forEach(u => {
console.log('u', u)
if (u.id == id){
proj.value = u
}
})
})
</script>
<style lang="less">
.page{
background-color: #F3F4F6;
}
.card {
position: relative;
margin: 16px;
border-radius: 6px;
// overflow: hidden;
box-sizing: border-box;
border: 1.5px solid var(--bg-color-demo, #fff);
border-color: var(--td-success-color-4);
}
.card--active {
border-color: var(--td-brand-color);
}
.card--active::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
width: 0;
border: 14px solid var(--td-success-color-4);
border-bottom-color: transparent;
border-right-color: transparent;
}
.card__icon {
color: var(--td-text-color-anti);
position: absolute;
left: 1.5px;
top: 1.5px;
z-index: 1;
}
/* 横向布局 */
.horizontal-box {
width: calc(100% - 32px);
display: flex;
align-items: start;
margin: 16px;
white-space: nowrap
}
.horizontal-box .card {
flex: 1;
margin: 0;
}
.horizontal-box .card + .card {
margin-left: 12px;
}
.horizontal-box .card::after {
border-width: 12px;
}
.horizontal-box .card__icon {
font-size: 12px;
}
.proj-line{
width: calc(100vw - 8px);
border: 1px solid var(--td-success-color-4);
margin: 4px;
border-radius: 8px;
margin-bottom: 16px;
}
.proj-pic-line{
display:flex;
border-top: 1px solid var(--td-success-color-4);
}
.proj-line-block{
width: 50%;
}
.proj-pic-block{
width: 100%;
}
.proj-pic{
padding: 16px;
}
.proj-day{
padding-top: 8px;
display: flex;
justify-content: center;
}
.proj-label-line{
margin:16px;
}
.proj-label{
margin: 4px;
padding: 4px 12px 4px 12px;
line-height: 36px;
border-radius: 16px;
color: #000;
white-space: nowrap;
border: 1px solid var(--td-success-color-4);
}
.proj-label-active{
color: #fff;
background-color: var(--td-success-color-4);
}
.proj-name-line{
border-bottom: 1px solid var(--td-success-color-4);
// border-radius: 8px;
}
.proj-name{
border-radius: 8px;
}
.t-checkbox--block {
padding: 4px;
padding-left: 16px;
}
.t-cell__note{
color: #000;
}
.proj-note{
white-space: pre-line; /* 或 pre-wrap / pre */
}
</style>

170
src/views/ProdListView.vue Normal file
View File

@ -0,0 +1,170 @@
<template>
<div class="page">
<div v-for="(proj, idx) in PROJECTS" class="proj-line">
<div class="proj-name-line">
<t-cell :title="`${(idx+1)+ '. ' + proj.name}`" class="line-start line-end" style="border-top-left-radius:8px;border-top-right-radius:8px;" arrow @click="toProjDetail(proj.id)">
<template #title>
<div style="color:#fff;">{{(idx+1)}} {{proj.name}}</div>
</template>
<template #note>
<div style="min-width: 60px;">¥ {{proj.price}}</div>
</template>
</t-cell>
<t-cell title="适用人群" class="line-end" :note="`${proj.audience}`" @click="toProjDetail(proj.id)" ></t-cell>
<t-cell v-if="proj.sub" :title="proj.sub" style="border-radius: 8px;"></t-cell>
<t-cell title="客户购买链接" style="border-radius: 8px;" arrow note="开发中" @click="toPayPage"></t-cell>
</div>
</div>
</div>
<div class="empty-bar"></div>
<div class="empty-bar"></div>
</template>
<script lang="ts" setup>
import { Icon as TIcon } from 'tdesign-icons-vue-next';
import { ref, onMounted } from 'vue';
import {useRoute, useRouter} from 'vue-router'
import {PROJECTS, DISCOUNT_TABLE} from '../api/prod'
import {Message} from 'tdesign-mobile-vue'
const router = useRouter()
const search = ref([])
const toProjDetail = (id) => {
router.push({name: 'prod_detail', params:{id}})
}
const toPayPage = () => {
Message.warning("开发中")
}
onMounted(() =>{
})
</script>
<style lang="less">
.page{
background-color: #F3F4F6;
}
.card {
position: relative;
margin: 16px;
border-radius: 6px;
// overflow: hidden;
box-sizing: border-box;
border: 1.5px solid var(--bg-color-demo, #fff);
border-color: var(--td-success-color-4);
}
.card--active {
border-color: var(--td-brand-color);
}
.card--active::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
width: 0;
border: 14px solid var(--td-success-color-4);
border-bottom-color: transparent;
border-right-color: transparent;
}
.card__icon {
color: var(--td-text-color-anti);
position: absolute;
left: 1.5px;
top: 1.5px;
z-index: 1;
}
/* 横向布局 */
.horizontal-box {
width: calc(100% - 32px);
display: flex;
align-items: start;
margin: 16px;
white-space: nowrap
}
.horizontal-box .card {
flex: 1;
margin: 0;
}
.horizontal-box .card + .card {
margin-left: 12px;
}
.horizontal-box .card::after {
border-width: 12px;
}
.horizontal-box .card__icon {
font-size: 12px;
}
.proj-line{
width: calc(100vw - 8px);
margin: 4px;
border-radius: 8px;
margin-bottom: 16px;
}
.proj-pic-line{
display:flex;
border-top: 1px solid var(--td-success-color-4);
}
.proj-line-block{
width: 50%;
}
.proj-pic-block{
width: 100%;
}
.proj-pic{
padding: 16px;
}
.proj-day{
padding-top: 8px;
display: flex;
justify-content: center;
}
.proj-label-line{
margin:16px;
}
.proj-label{
margin: 4px;
padding: 4px 12px 4px 12px;
line-height: 36px;
border-radius: 16px;
color: #000;
white-space: nowrap;
border: 1px solid var(--td-success-color-4);
}
.proj-label-active{
color: #fff;
background-color: var(--td-success-color-4);
}
.proj-name-line{
border-bottom: 1px solid var(--td-success-color-4);
// border-radius: 8px;
}
.proj-name{
border-radius: 8px;
}
.t-checkbox--block {
padding: 4px;
padding-left: 16px;
}
.proj-title{
// background-color: var(--td-success-color-4);
// color: #fff !important;
}
.t-cell__note{
color: #000;
}
.proj-note{
white-space: pre-line; /* 或 pre-wrap / pre */
}
</style>