Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
CFFP-HB
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chao Sun
CFFP-HB
Commits
d836b97a
Commit
d836b97a
authored
Oct 29, 2025
by
Sweet Zhang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
对接产品佣金
parent
a7784bac
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
620 additions
and
4 deletions
+620
-4
api/api.ts
+4
-1
environments/environment.ts
+1
-1
myPackageA/product-list/commission-detail.vue
+318
-0
myPackageA/product-list/product-commission.vue
+283
-0
myPackageA/product-list/product-list.vue
+1
-1
pages.json
+12
-1
pages/personalCenter/personalCenter.vue
+1
-0
No files found.
api/api.ts
View file @
d836b97a
...
...
@@ -439,6 +439,9 @@ export default {
// 数据字典查询
metaQuery
(
params
){
return
request
(
`
${
apiURL
}
/metadata/dropOptionsQuery`
,
'POST'
,
params
)
},
// 持牌人佣金查询
queryRate
(
params
){
return
request
(
`
${
apiURL
}
/insurance_product/query/rate?planBizId=
${
params
.
planBizId
}
&userId=
${
params
.
userId
}
`
,
"GET"
)
}
}
environments/environment.ts
View file @
d836b97a
...
...
@@ -49,7 +49,7 @@ const config = {
stage
,
prod
}
let
env
=
'
prod
'
;
let
env
=
'
dev
'
;
let
baseURL
=
config
[
env
].
base_url
;
let
apiURL
=
config
[
env
].
api_url
;
...
...
myPackageA/product-list/commission-detail.vue
0 → 100644
View file @
d836b97a
<
template
>
<view
class=
"container"
>
<!-- 水印容器 -->
<view
class=
"watermark-container"
>
<view
class=
"watermark"
v-for=
"i in 24"
:key=
"i"
>
<text
class=
"watermark-text"
>
{{
userId
}}
</text>
</view>
</view>
<!-- 费率详情 -->
<!-- 费率详情 -->
<view
class=
"info-card"
v-if=
"rateData && rateData.length > 0"
>
<view
class=
"info-title"
>
费率详情
</view>
<view
class=
"contract-detail"
>
<!-- 表格 -->
<view
class=
"detail-table"
>
<!-- 保险公司 -->
<view
class=
"table-row"
>
<view
class=
"table-cell first-column"
>
<text
class=
"cell-text"
>
保险公司
</text>
</view>
<view
class=
"table-cell"
v-for=
"(plan, index) in rateData"
:key=
"index"
>
<text
class=
"cell-text"
>
{{
plan
.
companyName
}}
</text>
</view>
</view>
<!-- 产品名称 -->
<view
class=
"table-row"
>
<view
class=
"table-cell first-column"
>
<text
class=
"cell-text"
>
产品名称
</text>
</view>
<view
class=
"table-cell"
v-for=
"(plan, index) in rateData"
:key=
"index"
>
<text
class=
"cell-text"
>
{{
plan
.
planName
}}
</text>
</view>
</view>
<!-- 条件 -->
<view
class=
"table-row"
>
<view
class=
"table-cell first-column"
>
<text
class=
"cell-text"
>
条件
</text>
</view>
<view
class=
"table-cell"
v-for=
"(plan, index) in rateData"
:key=
"index"
>
<text
class=
"cell-text"
>
供款年期 =
{{
plan
.
term
}}
</text>
</view>
</view>
<!-- 各年保费 -->
<view
class=
"table-row"
v-for=
"year in maxYears"
:key=
"year"
>
<view
class=
"table-cell first-column"
>
<text
class=
"cell-text"
>
保费(第
{{
year
}}
年)
</text>
</view>
<view
class=
"table-cell"
v-for=
"(plan, index) in rateData"
:key=
"index"
>
<text
class=
"cell-text commission-value"
>
{{
getCommissionRate
(
plan
,
year
)
}}
</text>
</view>
</view>
</view>
</view>
</view>
<!-- 加载状态 -->
<view
class=
"loading"
v-if=
"loading"
>
<text>
加载中...
</text>
</view>
<!-- 错误状态 -->
<view
class=
"error"
v-if=
"error"
>
<text>
{{
error
}}
</text>
</view>
</view>
</
template
>
<
script
setup
>
import
{
ref
,
onMounted
,
computed
}
from
'vue'
import
{
useRouter
,
useRoute
}
from
'vue-router'
;
import
api
from
'@/api/api'
;
// 计算最大年份数
const
maxYears
=
ref
(
7
)
// 获取指定年份的佣金率
const
getCommissionRate
=
(
plan
,
year
)
=>
{
const
rate
=
plan
.
termRateResponseList
.
find
(
item
=>
item
.
issueNumber
===
year
)
return
rate
?
`
${
rate
.
calculateRate
}
%`
:
'0%'
}
// 路由实例
const
router
=
useRouter
();
const
route
=
useRoute
();
// 响应式数据
const
rateData
=
ref
([])
const
userId
=
ref
(
''
)
const
loading
=
ref
(
false
)
const
error
=
ref
(
null
)
// 获取页面参数
const
planBizId
=
ref
(
route
.
query
.
planBizId
||
''
)
const
planName
=
ref
(
decodeURIComponent
(
route
.
query
.
planName
||
''
))
// 获取费率数据
const
fetchRateData
=
async
()
=>
{
if
(
!
planBizId
.
value
)
return
loading
.
value
=
true
error
.
value
=
null
try
{
const
params
=
{
planBizId
:
planBizId
.
value
,
userId
:
localStorage
.
getItem
(
'cffp_userId'
)
}
const
response
=
await
api
.
queryRate
(
params
)
// 模拟API延迟
await
new
Promise
(
resolve
=>
setTimeout
(
resolve
,
800
))
if
(
response
.
success
)
{
rateData
.
value
=
response
.
data
}
}
catch
(
err
)
{
error
.
value
=
'获取费率数据失败'
console
.
error
(
'API调用失败:'
,
err
)
}
finally
{
loading
.
value
=
false
}
}
// 生命周期
onMounted
(()
=>
{
userId
.
value
=
localStorage
.
getItem
(
'cffp_userId'
)
||
''
fetchRateData
()
})
</
script
>
<
style
scoped
>
.container
{
padding
:
20px
;
background-color
:
#f5f7fa
;
min-height
:
100vh
;
position
:
relative
;
}
.watermark-text
{
font-size
:
24px
;
color
:
#007AFF
;
font-weight
:
bold
;
white-space
:
nowrap
;
}
/* 水印样式 - 铺满屏幕版本 */
.watermark-container
{
position
:
fixed
;
top
:
0
;
left
:
0
;
width
:
100%
;
height
:
100%
;
pointer-events
:
none
;
z-index
:
99
;
overflow
:
hidden
;
}
.watermark
{
position
:
absolute
;
opacity
:
0.06
;
transform
:
rotate
(
-30deg
);
font-size
:
16px
;
color
:
#666
;
font-weight
:
500
;
white-space
:
nowrap
;
}
/* 4列6行的规律网格布局,铺满整个屏幕 */
.watermark
:nth-child
(
1
)
{
top
:
8%
;
left
:
5%
;
}
.watermark
:nth-child
(
2
)
{
top
:
8%
;
left
:
30%
;
}
.watermark
:nth-child
(
3
)
{
top
:
8%
;
left
:
55%
;
}
.watermark
:nth-child
(
4
)
{
top
:
8%
;
left
:
80%
;
}
.watermark
:nth-child
(
5
)
{
top
:
25%
;
left
:
2%
;
}
.watermark
:nth-child
(
6
)
{
top
:
25%
;
left
:
27%
;
}
.watermark
:nth-child
(
7
)
{
top
:
25%
;
left
:
52%
;
}
.watermark
:nth-child
(
8
)
{
top
:
25%
;
left
:
77%
;
}
.watermark
:nth-child
(
9
)
{
top
:
42%
;
left
:
8%
;
}
.watermark
:nth-child
(
10
)
{
top
:
42%
;
left
:
33%
;
}
.watermark
:nth-child
(
11
)
{
top
:
42%
;
left
:
58%
;
}
.watermark
:nth-child
(
12
)
{
top
:
42%
;
left
:
83%
;
}
.watermark
:nth-child
(
13
)
{
top
:
59%
;
left
:
2%
;
}
.watermark
:nth-child
(
14
)
{
top
:
59%
;
left
:
27%
;
}
.watermark
:nth-child
(
15
)
{
top
:
59%
;
left
:
52%
;
}
.watermark
:nth-child
(
16
)
{
top
:
59%
;
left
:
77%
;
}
.watermark
:nth-child
(
17
)
{
top
:
76%
;
left
:
8%
;
}
.watermark
:nth-child
(
18
)
{
top
:
76%
;
left
:
33%
;
}
.watermark
:nth-child
(
19
)
{
top
:
76%
;
left
:
58%
;
}
.watermark
:nth-child
(
20
)
{
top
:
76%
;
left
:
83%
;
}
.watermark
:nth-child
(
21
)
{
top
:
93%
;
left
:
2%
;
}
.watermark
:nth-child
(
22
)
{
top
:
93%
;
left
:
27%
;
}
.watermark
:nth-child
(
23
)
{
top
:
93%
;
left
:
52%
;
}
.watermark
:nth-child
(
24
)
{
top
:
93%
;
left
:
77%
;
}
.loading
,
.error
{
text-align
:
center
;
padding
:
20px
;
color
:
#666
;
position
:
relative
;
z-index
:
10
;
}
.error
{
color
:
#FF6B6B
;
}
.contract-detail
{
border
:
1px
solid
#dcdfe6
;
border-radius
:
4px
;
overflow
:
hidden
;
margin-top
:
10px
;
}
.contract-title
{
background
:
#f5f7fa
;
padding
:
12px
15px
;
border-bottom
:
1px
solid
#dcdfe6
;
}
.contract-name
{
font-size
:
14px
;
font-weight
:
600
;
color
:
#303133
;
}
.detail-table
{
background
:
white
;
overflow-x
:
auto
;
}
.table-row
{
display
:
flex
;
min-width
:
600px
;
border-bottom
:
1px
solid
#ebeef5
;
}
.table-row
:last-child
{
border-bottom
:
none
;
}
.table-row.header-row
{
background
:
#fafafa
;
font-weight
:
600
;
}
.table-cell
{
flex
:
1
;
padding
:
12px
15px
;
min-height
:
44px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
text-align
:
center
;
border-right
:
1px
solid
#ebeef5
;
}
.table-cell
:last-child
{
border-right
:
none
;
}
.table-cell.first-column
{
background
:
#fafafa
;
width
:
60px
;
flex
:
none
;
justify-content
:
flex-start
;
}
.cell-text
{
font-size
:
14px
;
color
:
#606266
;
line-height
:
1.4
;
}
.header-row
.cell-text
{
color
:
#303133
;
font-weight
:
600
;
}
.commission-value
{
color
:
#007AFF
;
font-weight
:
600
;
}
/* 其他样式保持不变 */
.info-card
{
background-color
:
white
;
border-radius
:
8px
;
padding
:
15px
;
margin-bottom
:
15px
;
box-shadow
:
0
2px
4px
rgba
(
0
,
0
,
0
,
0.05
);
position
:
relative
;
z-index
:
10
;
}
.info-title
{
font-size
:
16px
;
font-weight
:
bold
;
margin-bottom
:
10px
;
color
:
#333
;
}
</
style
>
\ No newline at end of file
myPackageA/product-list/product-commission.vue
0 → 100644
View file @
d836b97a
<
template
>
<view
class=
"container"
>
<!-- 头部 -->
<view
class=
"header"
>
<view
class=
"title"
>
产品查询
</view>
</view>
<!-- 搜索区域 -->
<view
class=
"search-box"
>
<input
class=
"search-input"
type=
"text"
placeholder=
"请输入产品名称"
v-model=
"searchKeyword"
@
input=
"handleSearch"
/>
<view
class=
"search-icon"
>
🔍
</view>
</view>
<!-- 产品列表 -->
<view
class=
"product-list"
v-if=
"!loading && filteredProducts.length > 0"
>
<view
class=
"product-item"
v-for=
"product in filteredProducts"
:key=
"product.planBizId"
@
click=
"goToCommissionDetail(product)"
>
<view
class=
"product-header"
>
<view
class=
"product-name"
>
{{
product
.
planName
}}
</view>
<view
class=
"product-term"
>
{{
product
.
term
}}
年
</view>
</view>
<view
class=
"product-info"
>
<view
class=
"info-item"
>
<text
class=
"info-label"
>
保险公司:
</text>
<text
class=
"info-value"
>
{{
product
.
companyName
}}
</text>
</view>
<view
class=
"info-item"
>
<text
class=
"info-label"
>
险种类别:
</text>
<text
class=
"info-value"
>
{{
getCategoryName
(
product
.
category
)
}}
</text>
</view>
<view
class=
"info-item"
>
<text
class=
"info-label"
>
适用年龄:
</text>
<text
class=
"info-value"
>
{{
product
.
minAge
}}
-
{{
product
.
maxAge
}}
岁
</text>
</view>
</view>
<view
class=
"arrow"
>
›
</view>
</view>
</view>
<!-- 加载状态 -->
<view
class=
"loading"
v-if=
"loading"
>
<text>
加载中...
</text>
</view>
<!-- 空状态 -->
<view
class=
"empty"
v-if=
"!loading && filteredProducts.length === 0"
>
<text>
暂无产品数据
</text>
</view>
</view>
</
template
>
<
script
setup
>
import
{
ref
,
computed
,
onMounted
}
from
'vue'
// 响应式数据
const
searchKeyword
=
ref
(
''
)
const
products
=
ref
([])
const
loading
=
ref
(
false
)
// 模拟产品数据 - 实际应从API获取
const
mockProducts
=
[
{
"planBizId"
:
"1387023335996522496"
,
"planName"
:
"環宇盈活儲蓄保險計劃"
,
"category"
:
"SAV"
,
"companyName"
:
"友邦保險(國際)有限公司"
,
"term"
:
3
,
"minAge"
:
0
,
"maxAge"
:
60
},
{
"planBizId"
:
"1387023335996522496"
,
"planName"
:
"環宇盈活儲蓄保險計劃"
,
"category"
:
"SAV"
,
"companyName"
:
"友邦保險(國際)有限公司"
,
"term"
:
5
,
"minAge"
:
0
,
"maxAge"
:
65
},
{
"planBizId"
:
"1387023335996522497"
,
"planName"
:
"卓越醫療保障計劃"
,
"category"
:
"MED"
,
"companyName"
:
"保誠保險有限公司"
,
"term"
:
10
,
"minAge"
:
18
,
"maxAge"
:
55
},
{
"planBizId"
:
"1387023335996522498"
,
"planName"
:
"豐盛退休年金"
,
"category"
:
"RET"
,
"companyName"
:
"宏利人壽保險公司"
,
"term"
:
20
,
"minAge"
:
30
,
"maxAge"
:
50
}
]
// 计算属性 - 筛选后的产品列表
const
filteredProducts
=
computed
(()
=>
{
if
(
!
searchKeyword
.
value
)
{
return
products
.
value
}
return
products
.
value
.
filter
(
product
=>
product
.
planName
.
toLowerCase
().
includes
(
searchKeyword
.
value
.
toLowerCase
())
||
product
.
companyName
.
toLowerCase
().
includes
(
searchKeyword
.
value
.
toLowerCase
())
)
})
// 方法
const
handleSearch
=
()
=>
{
// 实际项目中可以添加防抖
}
const
goToCommissionDetail
=
(
product
)
=>
{
uni
.
navigateTo
({
url
:
`/myPackageA/product-list/commission-detail?planBizId=
${
product
.
planBizId
}
`
})
}
const
getCategoryName
=
(
category
)
=>
{
const
categoryMap
=
{
'SAV'
:
'储蓄保险'
,
'MED'
:
'医疗保险'
,
'RET'
:
'退休年金'
,
'LIF'
:
'人寿保险'
}
return
categoryMap
[
category
]
||
category
}
// 获取产品数据
const
fetchProducts
=
async
()
=>
{
loading
.
value
=
true
try
{
// 实际API调用
// const response = await uni.request({
// url: '/insurance_product/list',
// method: 'GET'
// })
// 模拟API延迟
await
new
Promise
(
resolve
=>
setTimeout
(
resolve
,
1000
))
products
.
value
=
mockProducts
}
catch
(
err
)
{
console
.
error
(
'获取产品列表失败:'
,
err
)
// 使用模拟数据
products
.
value
=
mockProducts
}
finally
{
loading
.
value
=
false
}
}
// 生命周期
onMounted
(()
=>
{
fetchProducts
()
})
</
script
>
<
style
scoped
>
.container
{
padding
:
20px
;
background-color
:
#f5f7fa
;
min-height
:
100vh
;
}
.header
{
text-align
:
center
;
margin-bottom
:
20px
;
}
.title
{
font-size
:
18px
;
font-weight
:
bold
;
color
:
#333
;
}
.search-box
{
position
:
relative
;
background-color
:
white
;
border-radius
:
8px
;
margin-bottom
:
15px
;
box-shadow
:
0
2px
4px
rgba
(
0
,
0
,
0
,
0.05
);
}
.search-input
{
width
:
100%
;
padding
:
12px
40px
12px
15px
;
border
:
1px
solid
#e0e0e0
;
border-radius
:
8px
;
font-size
:
14px
;
}
.search-icon
{
position
:
absolute
;
right
:
15px
;
top
:
50%
;
transform
:
translateY
(
-50%
);
color
:
#999
;
}
.product-list
{
margin-bottom
:
15px
;
}
.product-item
{
background-color
:
white
;
border-radius
:
8px
;
padding
:
15px
;
margin-bottom
:
10px
;
box-shadow
:
0
2px
4px
rgba
(
0
,
0
,
0
,
0.05
);
position
:
relative
;
}
.product-header
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
flex-start
;
margin-bottom
:
10px
;
}
.product-name
{
font-size
:
16px
;
font-weight
:
bold
;
color
:
#333
;
flex
:
1
;
}
.product-term
{
font-size
:
14px
;
color
:
#007AFF
;
background-color
:
#f0f7ff
;
padding
:
2px
8px
;
border-radius
:
4px
;
}
.product-info
{
margin-bottom
:
5px
;
}
.info-item
{
margin-bottom
:
5px
;
}
.info-label
{
color
:
#666
;
font-size
:
12px
;
}
.info-value
{
color
:
#333
;
font-size
:
12px
;
font-weight
:
500
;
}
.arrow
{
position
:
absolute
;
right
:
15px
;
top
:
50%
;
transform
:
translateY
(
-50%
);
color
:
#999
;
font-size
:
18px
;
}
.loading
,
.empty
{
text-align
:
center
;
padding
:
40px
20px
;
color
:
#666
;
}
</
style
>
\ No newline at end of file
myPackageA/product-list/product-list.vue
View file @
d836b97a
<
template
>
<scroll-view
@
scroll=
"handleScroll"
scroll-y=
"true"
class=
"scroll-Y"
>
<scroll-view
@
scroll=
"handleScroll"
scroll-y=
"true"
class=
"scroll-Y"
>
<view
class=
"product-list-page"
>
<!-- 顶部搜索和筛选 -->
<view
class=
"search-bar"
>
...
...
pages.json
View file @
d836b97a
...
...
@@ -585,7 +585,18 @@
"style"
:
{
"navigationBarTitleText"
:
"产品对比"
}
}
},{
"path"
:
"product-list/product-commission"
,
"style"
:
{
"navigationBarTitleText"
:
"持牌人佣金"
}
},
{
"path"
:
"product-list/commission-detail"
,
"style"
:
{
"navigationBarTitleText"
:
"佣金详情"
}
}
]
},{
...
...
pages/personalCenter/personalCenter.vue
View file @
d836b97a
...
...
@@ -224,6 +224,7 @@
{
key
:
'policies'
,
title
:
'制度'
,
icon
:
'icon-xiaoshoue'
,
link
:
'/pages/personalCenter/detail'
,
isOpen
:
true
,
isShow
:
false
,
identity
:
true
,
type
:
4
},
{
key
:
'products'
,
title
:
'产品分析'
,
icon
:
'icon-shujufenxi'
,
link
:
'/pages/personalCenter/detail'
,
isOpen
:
true
,
isShow
:
false
,
identity
:
true
,
type
:
3
},
{
key
:
'cases'
,
title
:
'案例分享'
,
icon
:
'icon-shiyongjiaocheng'
,
link
:
'/pages/personalCenter/detail'
,
isOpen
:
true
,
isShow
:
false
,
identity
:
true
,
type
:
2
},
{
key
:
'commission'
,
title
:
'持牌人佣金'
,
icon
:
'icon-shiyongjiaocheng'
,
link
:
'/myPackageA/product-list/product-commission'
,
isOpen
:
true
,
isShow
:
false
,
identity
:
true
},
],
},{
id
:
'04'
,
categoryName
:
'海外资产配置'
,
children
:[
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment