Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
飞
飞鹤小程序
Project
Project
Details
Activity
Releases
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
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
FH
飞鹤小程序
Commits
fc9295c6
Commit
fc9295c6
authored
Sep 08, 2025
by
张九刚
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into feature/20250901_share
parents
58fc3df5
27e1aa78
Changes
29
Show whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
6809 additions
and
949 deletions
+6809
-949
.DS_Store
.DS_Store
+0
-0
.gitignore
.gitignore
+0
-1
launch.json
.hbuilderx/launch.json
+24
-0
xingmaLab.js
api/xingmaLab.js
+40
-0
yearGift.vue
components/pointRightsCom/yearGift.vue
+4
-4
IMAGES.md
components/xingmaLab/IMAGES.md
+229
-0
README.md
components/xingmaLab/README.md
+358
-0
Xingmalabconfirmpop.vue
components/xingmaLab/Xingmalabconfirmpop.vue
+130
-0
Xingmalabnotimepop.vue
components/xingmaLab/Xingmalabnotimepop.vue
+101
-0
config.js
components/xingmaLab/config.js
+146
-0
example.vue
components/xingmaLab/example.vue
+268
-0
xingmalabImages.js
components/xingmaLab/xingmalabImages.js
+17
-0
home.json
mock/home.json
+585
-517
my.json
mock/my.json
+446
-417
pages.json
pages.json
+29
-8
README.md
pages/XingmaLabDetailPage/README.md
+154
-0
XingmaLabDetailPage.less
pages/XingmaLabDetailPage/XingmaLabDetailPage.less
+254
-0
XingmaLabDetailPage.vue
pages/XingmaLabDetailPage/XingmaLabDetailPage.vue
+400
-0
config.js
pages/XingmaLabDetailPage/config.js
+54
-0
CHANGELOG.md
pages/XingmaLabPublishPage/CHANGELOG.md
+93
-0
README.md
pages/XingmaLabPublishPage/README.md
+74
-0
XingmaLabPublishPage.less
pages/XingmaLabPublishPage/XingmaLabPublishPage.less
+693
-0
XingmaLabPublishPage.vue
pages/XingmaLabPublishPage/XingmaLabPublishPage.vue
+691
-0
config.js
pages/XingmaLabPublishPage/config.js
+114
-0
test-popup.vue
pages/XingmaLabPublishPage/test-popup.vue
+147
-0
xingmaLab.less
pages/xingmaLab/xingmaLab.less
+752
-0
xingmaLab.vue
pages/xingmaLab/xingmaLab.vue
+744
-0
xingmaLab.js
stores/xingmaLab.js
+167
-0
Integral.vue
views/Integral.vue
+95
-2
No files found.
.DS_Store
0 → 100644
View file @
fc9295c6
File added
.gitignore
View file @
fc9295c6
unpackage/
dist/
static/
node_modules/
.DS_Store
\ No newline at end of file
.hbuilderx/launch.json
View file @
fc9295c6
//
{
//
//
launch.json
配置了启动调试时相关设置,configurations下节点名称可为
app-plus/h
5
/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp
-360
/
//
//
launchtype项可配置值为local或remote
,
local代表前端连本地云函数,remote代表前端连云端云函数
//
"version"
:
"0.0"
,
//
"configurations"
:
[
//
{
//
"default"
:
{
//
"launchtype"
:
"local"
//
},
//
"mp-weixin"
:
{
//
"launchtype"
:
"local"
//
},
//
"type"
:
"uniCloud"
//
},
//
{
//
"openVueDevtools"
:
false
,
//
"type"
:
"uni-app:miniProgram"
//
},
//
{
//
"openVueDevtools"
:
false
,
//
"type"
:
"uni-app:h5"
//
}
//
]
//
}
{
"version"
:
"1.0"
,
"configurations"
:
[
...
...
api/xingmaLab.js
0 → 100644
View file @
fc9295c6
import
requestModule
from
'./request.js'
const
{
api
}
=
requestModule
/**
* 星妈会藏馆
* @returns
*/
export
const
fetchRecordList
=
(
pageNum
,
pageSize
)
=>
api
.
get
(
'/c/lab/record/list'
,
{
pageNum
:
pageNum
,
pageSize
:
pageSize
})
/**
* 我的收藏
* @returns
*/
export
const
fetchFavoriteList
=
(
pageNum
,
pageSize
)
=>
api
.
get
(
'/c/lab/favorite/list'
,
{
pageNum
:
pageNum
,
pageSize
:
pageSize
})
/**
* 我的藏品
* @returns
*/
export
const
fetchRecordMyrecords
=
(
pageNum
,
pageSize
)
=>
api
.
get
(
'/c/lab/record/myRecords'
,
{
pageNum
:
pageNum
,
pageSize
:
pageSize
})
export
const
fetchRecordIndex
=
()
=>
api
.
get
(
'/c/lab/home'
)
export
const
fetchRecordPublish
=
(
data
)
=>
api
.
post
(
'/c/lab/record/create'
,
data
)
export
const
fetchRecordDetail
=
(
data
)
=>
api
.
get
(
'/c/lab/record/detail'
,
data
)
export
const
fetchFavoriteAdd
=
(
data
)
=>
api
.
get
(
'/c/lab/favorite/add'
,
data
)
export
const
fetchFavoriteRemove
=
(
data
)
=>
api
.
get
(
'/c/lab/favorite/remove'
,
data
)
components/pointRightsCom/yearGift.vue
View file @
fc9295c6
...
...
@@ -144,7 +144,7 @@
</
template
>
<
script
setup
>
import
{
getCurrentInstance
,
computed
,
onMounted
}
from
'vue'
import
{
getCurrentInstance
,
computed
,
onMounted
}
from
'vue'
import
{
YEAR_GIFT_IMAGES
}
from
'./yearGiftImages.js'
import
md
from
'../../md.js'
...
...
@@ -205,7 +205,7 @@ onMounted(() => {
xcxComponentExposure
:
"true"
,
pageName
:
"积分服务页"
,
componentName
:
"会员权益"
,
componentContent
:
"周岁礼-"
+
buttonInfo
.
value
.
text
componentContent
:
"周岁礼-"
+
buttonInfo
.
value
.
text
});
})
// 按钮点击事件处理
...
...
@@ -214,7 +214,7 @@ const handleButtonClick = () => {
xcxComponentClick
:
"true"
,
pageName
:
"积分服务页"
,
componentName
:
"会员权益"
,
componentContent
:
"周岁礼-"
+
buttonInfo
.
value
.
text
componentContent
:
"周岁礼-"
+
buttonInfo
.
value
.
text
});
if
(
buttonInfo
.
value
.
action
===
'upgrade'
)
{
// 跳转到升级页面
...
...
@@ -224,7 +224,7 @@ const handleButtonClick = () => {
}
else
if
(
buttonInfo
.
value
.
action
===
'view'
)
{
// 跳转到查看页面
uni
.
navigateTo
({
url
:
'/pages/webview/webview?url=https://member.feihe.com/memberH5/#/memberGrowthGift?activityCode=hyczl&sceneCode=WXG07'
url
:
`/pages/webview/webview?url=
${
encodeURIComponent
(
'https://member.feihe.com/memberH5/#/memberGrowthGift?activityCode=hyczl&sceneCode=WXG07'
)}
`
});
}
}
...
...
components/xingmaLab/IMAGES.md
0 → 100644
View file @
fc9295c6
# XingmaLab 弹窗组件图片资源说明
本文档说明 XingmaLab 弹窗组件所需的图片资源,参考
`babyClass`
组件的图片管理方式。
## 图片配置结构
图片资源通过
`xingmalabImages.js`
文件进行配置管理,采用常量对象的方式:
```
javascript
export
const
XINGMALAB_IMAGES
=
{
CONFIRM
:
{
BG
:
`XingmaLabPop/v1/XingmaLabConfirmPopBg.png`
,
CONFIRM_BTN
:
`XingmaLabPop/v1/XingmaLabConfirmPopConfirmBtn.png`
,
CANCEL_BTN
:
`XingmaLabPop/v1/XingmaLabCancelBtn.png`
},
NO_TIME
:
{
BG
:
`XingmaLabPop/v1/XingmaLabNoTimePopBg.png`
,
BTN
:
`XingmaLabPop/v1/XingmaLabNoTimePopBtn.png`
}
}
```
## 目录结构
```
static/
└── XingmaLabPop/
└── v1/
├── XingmaLabConfirmPopBg.png # 确认弹窗背景图片
├── XingmaLabConfirmPopConfirmBtn.png # 确认弹窗确认按钮图片
├── XingmaLabCancelBtn.png # 确认弹窗取消按钮图片
├── XingmaLabNoTimePopBg.png # 无时间弹窗背景图片
└── XingmaLabNoTimePopBtn.png # 无时间弹窗按钮图片
```
## 图片规格要求
### 确认弹窗图片
#### 1. XingmaLabConfirmPopBg.png (背景图片)
-
**尺寸**
: 618rpx × 557rpx
-
**格式**
: PNG
-
**用途**
: 确认弹窗的背景图片
-
**设计要求**
: 透明背景,包含弹窗框架和装饰元素
#### 2. XingmaLabConfirmPopConfirmBtn.png (确认按钮)
-
**尺寸**
: 275rpx × 97rpx
-
**格式**
: PNG
-
**用途**
: 确认按钮的图片
-
**设计要求**
: 透明背景,包含按钮文字和样式
#### 3. XingmaLabCancelBtn.png (取消按钮)
-
**尺寸**
: 279rpx × 101rpx
-
**格式**
: PNG
-
**用途**
: 取消按钮的图片
-
**设计要求**
: 透明背景,包含按钮文字和样式
### 无时间弹窗图片
#### 1. XingmaLabNoTimePopBg.png (背景图片)
-
**尺寸**
: 618rpx × 460rpx
-
**格式**
: PNG
-
**用途**
: 无时间弹窗的背景图片
-
**设计要求**
: 透明背景,包含弹窗框架和提示信息
#### 2. XingmaLabNoTimePopBtn.png (按钮)
-
**尺寸**
: 466rpx × 97rpx
-
**格式**
: PNG
-
**用途**
: 无时间弹窗的按钮图片
-
**设计要求**
: 透明背景,包含按钮文字和样式
## 图片命名规范
### 命名规则
-
使用 PascalCase 命名方式
-
包含组件类型和元素类型
-
版本号使用小写字母
### 命名示例
```
XingmaLabConfirmPopBg.png # 确认弹窗背景
XingmaLabConfirmPopConfirmBtn.png # 确认弹窗确认按钮
XingmaLabCancelBtn.png # 确认弹窗取消按钮
XingmaLabNoTimePopBg.png # 无时间弹窗背景
XingmaLabNoTimePopBtn.png # 无时间弹窗按钮
```
## 版本管理
### 版本结构
```
XingmaLabPop/
├── v1/ # 当前版本
│ ├── XingmaLabConfirmPopBg.png
│ ├── XingmaLabConfirmPopConfirmBtn.png
│ ├── XingmaLabCancelBtn.png
│ ├── XingmaLabNoTimePopBg.png
│ └── XingmaLabNoTimePopBtn.png
└── v2/ # 未来版本(可选)
└── ...
```
### 版本更新
1.
在
`xingmalabImages.js`
中修改
`version`
变量
2.
在
`static/XingmaLabPop/`
目录下创建新版本文件夹
3.
将新图片放入对应版本文件夹
4.
更新组件中的图片引用
## 图片优化建议
### 文件大小
-
单个图片文件大小控制在 100KB 以内
-
使用 PNG 格式保证透明背景效果
-
适当压缩图片,平衡质量和文件大小
### 设计规范
-
保持与整体 UI 风格一致
-
按钮图片包含合适的点击状态
-
背景图片支持不同屏幕尺寸适配
### 性能考虑
-
图片尺寸与显示尺寸保持一致
-
避免过大的图片文件影响加载速度
-
使用
`mode="aspectFit"`
确保图片正确显示
## 与 babyClass 组件的对比
### 相似点
1.
**图片配置方式**
: 都使用常量对象管理图片路径
2.
**目录结构**
: 都使用版本化的目录结构
3.
**命名规范**
: 都使用 PascalCase 命名方式
4.
**格式要求**
: 都使用 PNG 格式支持透明背景
### 不同点
1.
**图片数量**
: babyClass 有多个等级图片,xingmalab 只有弹窗图片
2.
**图片用途**
: babyClass 主要用于展示,xingmalab 主要用于交互
3.
**图片尺寸**
: babyClass 图片尺寸多样,xingmalab 图片尺寸相对固定
## 使用示例
### 在组件中使用
```
vue
<
template
>
<image
class=
"xingmalabconfirmpopbg"
:src=
"`$
{$baseUrl}${XINGMALAB_IMAGES.CONFIRM.BG}`"
mode="aspectFit"
>
</image>
</
template
>
<
script
setup
>
import
{
XINGMALAB_IMAGES
}
from
'./xingmalabImages.js'
</
script
>
```
### 动态获取图片路径
```
javascript
// 获取确认弹窗背景图片
const
confirmBgPath
=
XINGMALAB_IMAGES
.
CONFIRM
.
BG
// 获取无时间弹窗按钮图片
const
noTimeBtnPath
=
XINGMALAB_IMAGES
.
NO_TIME
.
BTN
```
## 注意事项
1.
**路径一致性**
: 确保
`xingmalabImages.js`
中的路径与实际文件路径一致
2.
**版本同步**
: 修改版本号时需要同步更新所有相关图片
3.
**图片质量**
: 确保图片清晰度满足不同设备显示需求
4.
**文件格式**
: 统一使用 PNG 格式,支持透明背景
5.
**命名规范**
: 严格遵循命名规范,便于维护和管理
6.
**尺寸匹配**
: 图片尺寸与 CSS 中定义的尺寸保持一致
7.
**性能优化**
: 合理控制图片文件大小,优化加载性能
8.
**跨平台兼容**
: 确保图片在不同平台上的显示效果一致
## 维护和更新
### 日常维护
-
定期检查图片文件是否存在
-
验证图片路径配置是否正确
-
监控图片加载性能
### 版本更新
-
记录版本更新日志
-
备份旧版本图片资源
-
测试新版本图片显示效果
### 问题排查
-
图片不显示:检查路径配置和文件存在性
-
图片变形:检查 CSS 尺寸设置
-
加载缓慢:优化图片文件大小和格式
## 弹窗布局结构
### 双层结构设计
弹窗组件采用双层结构设计,确保背景遮罩和弹窗内容正确显示:
```
弹窗容器 (100vw × 100vh)
├── 背景遮罩 (.mask)
│ ├── 位置: 覆盖整个屏幕
│ ├── 背景: rgba(0, 0, 0, 0.5) 半透明黑色
│ └── 层级: 基础层
└── 弹窗内容 (.popup-content)
├── 位置: 居中显示
├── 尺寸: 根据弹窗类型确定
└── 层级: 内容层 (z-index: 1)
```
### 布局特点
1.
**全屏覆盖**
: 弹窗容器使用
`position: fixed`
和
`100vw × 100vh`
2.
**居中显示**
: 使用
`display: flex`
和
`align-items: center`
,
`justify-content: center`
3.
**层级管理**
: 遮罩层和内容层使用不同的 z-index 值
4.
**响应式**
: 支持不同屏幕尺寸的适配
### 弹窗类型尺寸
#### 确认弹窗
-
**容器尺寸**
: 100vw × 100vh (全屏)
-
**内容尺寸**
: 618rpx × 557rpx
-
**背景图片**
: 618rpx × 557rpx
-
**确认按钮**
: 275rpx × 97rpx (位置: left: 318rpx, top: 408rpx)
-
**取消按钮**
: 279rpx × 101rpx (位置: left: 28rpx, top: 406rpx)
#### 无时间弹窗
-
**容器尺寸**
: 100vw × 100vh (全屏)
-
**内容尺寸**
: 618rpx × 460rpx
-
**背景图片**
: 618rpx × 460rpx
-
**按钮**
: 466rpx × 97rpx (位置: left: 76rpx, top: 312rpx)
components/xingmaLab/README.md
0 → 100644
View file @
fc9295c6
# XingmaLab 弹窗组件库
这是一个弹窗组件库,包含多个弹窗组件,用于不同的业务场景。参考
`babyClass`
组件的实现方式,使用简洁的图片标签和样式结构。
## 组件列表
### 1. Xingmalabconfirmpop - 确认弹窗组件
用于显示确认对话框,支持确认和取消操作。
### 2. Xingmalabnotimepop - 无时间弹窗组件
用于显示无时间状态的弹窗,通常只有一个按钮。
## 功能特性
-
支持显示/隐藏控制
-
响应式设计
-
图片资源集中配置管理
-
支持版本控制和图片更新
-
统一的样式和交互规范
-
支持自定义文案和样式
-
参考 babyClass 组件的简洁实现方式
## 实现方式
### 背景遮罩实现
弹窗组件使用双层结构实现背景遮罩效果:
```
vue
<
template
>
<view
class=
"xingmalabconfirmpop"
>
<!-- 背景遮罩 -->
<view
class=
"mask"
></view>
<!-- 弹窗内容 -->
<view
class=
"popup-content"
>
<!-- 弹窗图片和按钮 -->
</view>
</view>
</
template
>
```
### 遮罩样式
```
less
.mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5); // 半透明黑色背景
}
.popup-content {
position: relative;
z-index: 1; // 确保内容在遮罩之上
}
```
### 图片标签使用
组件使用
`<image>`
标签而不是
`<span>`
标签,提供更好的图片显示效果:
```
vue
<image
class=
"xingmalabconfirmpopbg"
:src=
"`${$baseUrl}${XINGMALAB_IMAGES.CONFIRM.BG}`"
mode=
"aspectFit"
></image>
```
### 图片配置管理
图片路径通过
`xingmalabImages.js`
文件集中管理:
```
javascript
export
const
XINGMALAB_IMAGES
=
{
CONFIRM
:
{
BG
:
`XingmaLabPop/v1/XingmaLabConfirmPopBg.png`
,
CONFIRM_BTN
:
`XingmaLabPop/v1/XingmaLabConfirmPopConfirmBtn.png`
,
CANCEL_BTN
:
`XingmaLabPop/v1/XingmaLabCancelBtn.png`
},
NO_TIME
:
{
BG
:
`XingmaLabPop/v1/XingmaLabNoTimePopBg.png`
,
BTN
:
`XingmaLabPop/v1/XingmaLabNoTimePopBtn.png`
}
}
```
### 样式结构
使用简洁的 Less 样式,直接定义尺寸和位置:
```
less
.xingmalabconfirmpop {
width: 750rpx;
height: 1624rpx;
left: 0rpx;
top: 0rpx;
position: absolute;
z-index: 9999;
.xingmalabconfirmpopbg {
width: 618rpx;
height: 557rpx;
left: 0rpx;
top: 0rpx;
position: absolute;
}
}
```
## 使用方法
### Xingmalabconfirmpop 组件
```
vue
<
template
>
<view>
<button
@
click=
"showConfirm = true"
>
显示确认弹窗
</button>
<Xingmalabconfirmpop
:visible=
"showConfirm"
title=
"确认操作"
confirm-text=
"确定"
cancel-text=
"取消"
@
confirm=
"handleConfirm"
@
cancel=
"handleCancel"
@
close=
"showConfirm = false"
/>
</view>
</
template
>
<
script
setup
>
import
{
ref
}
from
'vue'
import
Xingmalabconfirmpop
from
'@/components/xingmaLab/Xingmalabconfirmpop.vue'
const
showConfirm
=
ref
(
false
)
const
handleConfirm
=
()
=>
{
console
.
log
(
'用户点击了确认'
)
showConfirm
.
value
=
false
}
const
handleCancel
=
()
=>
{
console
.
log
(
'用户点击了取消'
)
showConfirm
.
value
=
false
}
</
script
>
```
### Xingmalabnotimepop 组件
```
vue
<
template
>
<view>
<button
@
click=
"showNoTime = true"
>
显示无时间弹窗
</button>
<Xingmalabnotimepop
:visible=
"showNoTime"
title=
"暂无时间"
@
button-click=
"handleButtonClick"
@
close=
"showNoTime = false"
/>
</view>
</
template
>
<
script
setup
>
import
{
ref
}
from
'vue'
import
Xingmalabnotimepop
from
'@/components/xingmaLab/Xingmalabnotimepop.vue'
const
showNoTime
=
ref
(
false
)
const
handleButtonClick
=
()
=>
{
console
.
log
(
'用户点击了按钮'
)
showNoTime
.
value
=
false
}
</
script
>
```
## 在发布页面中的使用
弹窗组件在
`XingmaLabPublishPage.vue`
中的使用示例:
```
vue
<!-- 确认发布弹窗 -->
<Xingmalabconfirmpop
:visible=
"showConfirmPopup"
title=
"确认发布"
confirm-text=
"确认发布"
cancel-text=
"取消"
@
confirm=
"handleConfirmPublish"
@
cancel=
"handleCancelPublish"
@
close=
"showConfirmPopup = false"
/>
<!-- 无次数弹窗 -->
<Xingmalabnotimepop
:visible=
"showNoTimePopup"
title=
"发布次数已用完"
@
button-click=
"handleNoTimeButtonClick"
@
close=
"showNoTimePopup = false"
/>
```
## Props
### Xingmalabconfirmpop Props
| 属性名 | 类型 | 默认值 | 说明 |
|--------|------|--------|------|
| visible | Boolean | false | 控制弹窗显示/隐藏 |
| title | String | '确认' | 弹窗标题 |
| confirmText | String | '确认' | 确认按钮文本 |
| cancelText | String | '取消' | 取消按钮文本 |
### Xingmalabnotimepop Props
| 属性名 | 类型 | 默认值 | 说明 |
|--------|------|--------|------|
| visible | Boolean | false | 控制弹窗显示/隐藏 |
| title | String | '暂无时间' | 弹窗标题 |
## Events
### Xingmalabconfirmpop Events
| 事件名 | 说明 | 回调参数 |
|--------|------|----------|
| confirm | 点击确认按钮时触发 | - |
| cancel | 点击取消按钮时触发 | - |
| close | 点击遮罩层时触发 | - |
### Xingmalabnotimepop Events
| 事件名 | 说明 | 回调参数 |
|--------|------|----------|
| button-click | 点击按钮时触发 | - |
| close | 点击遮罩层时触发 | - |
## 图片配置
组件使用集中化的图片配置管理,所有图片路径都在
`xingmalabImages.js`
文件中配置:
```
javascript
// 确认弹窗图片配置
CONFIRM
:
{
BG
:
`XingmaLabPop/v1/XingmaLabConfirmPopBg.png`
,
CONFIRM_BTN
:
`XingmaLabPop/v1/XingmaLabConfirmPopConfirmBtn.png`
,
CANCEL_BTN
:
`XingmaLabPop/v1/XingmaLabCancelBtn.png`
}
// 无时间弹窗图片配置
NO_TIME
:
{
BG
:
`XingmaLabPop/v1/XingmaLabNoTimePopBg.png`
,
BTN
:
`XingmaLabPop/v1/XingmaLabNoTimePopBtn.png`
}
```
### 图片目录结构
```
static/
└── XingmaLabPop/
└── v1/
├── XingmaLabConfirmPopBg.png # 确认弹窗背景
├── XingmaLabConfirmPopConfirmBtn.png # 确认弹窗确认按钮
├── XingmaLabCancelBtn.png # 确认弹窗取消按钮
├── XingmaLabNoTimePopBg.png # 无时间弹窗背景
└── XingmaLabNoTimePopBtn.png # 无时间弹窗按钮
```
## 按钮位置配置
### 与React版本对比
为了确保Vue组件与原始React组件完全一致,按钮位置配置如下:
#### Xingmalabconfirmpop 按钮位置
| 按钮 | React版本 (px) | Vue版本 (rpx) | 说明 |
|------|----------------|---------------|------|
| 确认按钮 | left: 318, top: 408 | left: 318, top: 408 | 完全一致 |
| 取消按钮 | left: 28, top: 406 | left: 28, top: 406 | 完全一致 |
#### Xingmalabnotimepop 按钮位置
| 按钮 | React版本 (px) | Vue版本 (rpx) | 说明 |
|------|----------------|---------------|------|
| 按钮 | left: 76, top: 312 | left: 76, top: 312 | 完全一致 |
### 定位方式
-
**React版本**
: 使用
`position: absolute`
和固定的
`left`
、
`top`
值
-
**Vue版本**
: 使用
`position: absolute`
和相同的
`left`
、
`top`
值
-
**单位转换**
: React使用
`px`
,Vue使用
`rpx`
,但数值保持一致
### 尺寸配置
-
**弹窗容器**
: 750rpx × 1624rpx (与React的750px × 1624px对应)
-
**背景图片**
: 618rpx × 557rpx (确认弹窗) / 618rpx × 460rpx (无时间弹窗)
-
**按钮尺寸**
: 与React版本完全一致
## 样式配置
```
javascript
// 按钮交互效果
transition
:
transform
0.2
s
ease
;
&
:
active
{
transform
:
scale
(
0.95
);
}
```
## 版本控制
组件支持版本控制,通过修改
`xingmalabImages.js`
中的
`version`
变量来管理不同版本的图片资源:
```
javascript
const
version
=
'v1'
// 当前版本
```
## 与 babyClass 组件的对比
### 相似点
1.
**图片标签使用**
: 都使用
`<image>`
标签
2.
**图片配置管理**
: 都使用独立的图片配置文件
3.
**样式结构**
: 都使用简洁的 Less 样式
4.
**版本控制**
: 都支持版本管理
### 不同点
1.
**业务逻辑**
: babyClass 处理等级展示,xingmalab 处理弹窗交互
2.
**图片数量**
: babyClass 有多个等级图片,xingmalab 只有弹窗图片
3.
**交互方式**
: babyClass 主要是展示,xingmalab 主要是交互
## 注意事项
1.
**图片资源**
: 需要准备对应的背景图片文件并放置在正确的目录结构中
2.
**样式单位**
: 组件使用 rpx 单位,确保跨平台兼容性
3.
**事件处理**
: 组件会发射标准事件,父组件可以监听处理
4.
**配置管理**
: 所有图片路径都在
`xingmalabImages.js`
中集中管理
5.
**版本更新**
: 如需更新图片,只需替换文件并更新版本号即可
6.
**组件复用**
: 多个弹窗组件共享相同的配置管理机制
7.
**发布流程**
: 在发布页面中,弹窗组件用于二次确认和次数限制提示
8.
**实现方式**
: 参考 babyClass 组件的简洁实现,使用 image 标签和直接样式
## 文件结构
```
components/xingmaLab/
├── Xingmalabconfirmpop.vue # 确认弹窗组件
├── Xingmalabnotimepop.vue # 无时间弹窗组件
├── xingmalabImages.js # 图片配置文件
├── config.js # 旧版配置文件(已废弃)
├── README.md # 使用说明
└── IMAGES.md # 图片资源说明
```
## 迁移说明
从旧版配置系统迁移到新的图片配置系统:
1.
**移除依赖**
: 不再依赖
`config.js`
中的复杂配置
2.
**简化导入**
: 直接导入
`XINGMALAB_IMAGES`
常量
3.
**简化样式**
: 移除计算属性,直接使用 CSS 样式
4.
**保持兼容**
: 按钮位置和尺寸与 React 版本完全一致
components/xingmaLab/Xingmalabconfirmpop.vue
0 → 100644
View file @
fc9295c6
<
template
>
<view
v-if=
"visible"
class=
"xingmalabconfirmpop"
@
click=
"handleOverlayClick"
>
<!-- 背景遮罩 -->
<view
class=
"mask"
></view>
<!-- 弹窗内容 -->
<view
class=
"popup-content"
>
<image
class=
"xingmalabconfirmpopbg"
:src=
"`$
{$baseUrl}${XINGMALAB_IMAGES.CONFIRM.BG}`" mode="aspectFit">
</image>
<image
class=
"xingmalabconfirmpopconfirmbtn"
:src=
"`$
{$baseUrl}${XINGMALAB_IMAGES.CONFIRM.CONFIRM_BTN}`"
mode="aspectFit" @click="handleConfirm">
</image>
<image
class=
"xingmalabcancelbtn"
:src=
"`$
{$baseUrl}${XINGMALAB_IMAGES.CONFIRM.CANCEL_BTN}`" mode="aspectFit"
@click="handleCancel">
</image>
</view>
</view>
</
template
>
<
script
setup
>
import
{
defineProps
,
defineEmits
,
getCurrentInstance
}
from
'vue'
import
{
XINGMALAB_IMAGES
}
from
'./xingmalabImages.js'
// 获取全局属性
const
{
proxy
}
=
getCurrentInstance
()
const
$baseUrl
=
proxy
.
$baseUrl
// 定义组件属性
const
props
=
defineProps
({
visible
:
{
type
:
Boolean
,
default
:
false
},
title
:
{
type
:
String
,
default
:
'确认'
},
confirmText
:
{
type
:
String
,
default
:
'确认'
},
cancelText
:
{
type
:
String
,
default
:
'取消'
}
})
// 定义组件事件
const
emit
=
defineEmits
([
'confirm'
,
'cancel'
,
'close'
])
// 确认按钮点击事件
const
handleConfirm
=
()
=>
{
emit
(
'confirm'
)
}
// 取消按钮点击事件
const
handleCancel
=
()
=>
{
emit
(
'cancel'
)
}
// 遮罩层点击事件
const
handleOverlayClick
=
(
event
)
=>
{
// 阻止事件冒泡
// event.stopPropagation()
// emit('close')
}
</
script
>
<
style
lang=
"less"
scoped
>
@import "../../common.less";
.xingmalabconfirmpop {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
.mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
.popup-content {
position: relative;
width: 618rpx;
height: 557rpx;
z-index: 1;
}
.xingmalabconfirmpopbg {
width: 618rpx;
height: 557rpx;
left: 0rpx;
top: 0rpx;
position: absolute;
}
.xingmalabconfirmpopconfirmbtn {
width: 275rpx;
height: 97rpx;
left: 318rpx;
top: 408rpx;
position: absolute;
transition: transform 0.2s ease;
&:active {
transform: scale(0.95);
}
}
.xingmalabcancelbtn {
width: 279rpx;
height: 101rpx;
left: 28rpx;
top: 406rpx;
position: absolute;
transition: transform 0.2s ease;
&:active {
transform: scale(0.95);
}
}
}
</
style
>
components/xingmaLab/Xingmalabnotimepop.vue
0 → 100644
View file @
fc9295c6
<
template
>
<view
v-if=
"visible"
class=
"xingmalabnotimepop"
@
click=
"handleOverlayClick"
>
<!-- 背景遮罩 -->
<view
class=
"mask"
></view>
<!-- 弹窗内容 -->
<view
class=
"popup-content"
>
<image
class=
"xingmalabnotimepopbg"
:src=
"`$
{$baseUrl}${XINGMALAB_IMAGES.NO_TIME.BG}`" mode="aspectFit">
</image>
<image
class=
"xingmalabnotimepopbtn"
:src=
"`$
{$baseUrl}${XINGMALAB_IMAGES.NO_TIME.BTN}`" mode="aspectFit" @click="handleButtonClick">
</image>
</view>
</view>
</
template
>
<
script
setup
>
import
{
defineProps
,
defineEmits
,
getCurrentInstance
}
from
'vue'
import
{
XINGMALAB_IMAGES
}
from
'./xingmalabImages.js'
// 获取全局属性
const
{
proxy
}
=
getCurrentInstance
()
const
$baseUrl
=
proxy
.
$baseUrl
// 定义组件属性
const
props
=
defineProps
({
visible
:
{
type
:
Boolean
,
default
:
false
},
title
:
{
type
:
String
,
default
:
'暂无时间'
}
})
// 定义组件事件
const
emit
=
defineEmits
([
'button-click'
,
'close'
])
// 按钮点击事件
const
handleButtonClick
=
()
=>
{
emit
(
'button-click'
)
}
// 遮罩层点击事件
const
handleOverlayClick
=
(
event
)
=>
{
// 阻止事件冒泡
// event.stopPropagation()
// emit('close')
}
</
script
>
<
style
lang=
"less"
scoped
>
@import "../../common.less";
.xingmalabnotimepop {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
.mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
.popup-content {
position: relative;
width: 618rpx;
height: 460rpx;
z-index: 1;
}
.xingmalabnotimepopbg {
width: 618rpx;
height: 460rpx;
left: 0rpx;
top: 0rpx;
position: absolute;
}
.xingmalabnotimepopbtn {
width: 466rpx;
height: 97rpx;
left: 76rpx;
top: 312rpx;
position: absolute;
transition: transform 0.2s ease;
&:active {
transform: scale(0.95);
}
}
}
</
style
>
\ No newline at end of file
components/xingmaLab/config.js
0 → 100644
View file @
fc9295c6
const
version
=
'v1'
// Xingmalabconfirmpop 组件配置
export
const
xingmalabConfirmConfig
=
{
// 图片资源路径配置
images
:
{
// 弹窗背景图片
background
:
`XingmaLabPop/
${
version
}
/XingmaLabConfirmPopBg.png`
,
// 确认按钮图片
confirmBtn
:
`XingmaLabPop/
${
version
}
/XingmaLabConfirmPopConfirmBtn.png`
,
// 取消按钮图片
cancelBtn
:
`XingmaLabPop/
${
version
}
/XingmaLabCancelBtn.png`
},
// 弹窗尺寸配置
dimensions
:
{
width
:
750
,
height
:
1624
,
background
:
{
width
:
618
,
height
:
557
,
image
:
`XingmaLabPop/
${
version
}
/XingmaLabConfirmPopBg.png`
},
confirmBtn
:
{
width
:
275
,
height
:
97
,
left
:
318
,
top
:
408
,
image
:
`XingmaLabPop/
${
version
}
/XingmaLabConfirmPopConfirmBtn.png`
},
cancelBtn
:
{
width
:
279
,
height
:
101
,
left
:
28
,
top
:
406
,
image
:
`XingmaLabPop/
${
version
}
/XingmaLabCancelBtn.png`
}
},
// 文案配置
texts
:
{
defaultTitle
:
'确认'
,
defaultConfirmText
:
'确认'
,
defaultCancelText
:
'取消'
},
// 样式配置
styles
:
{
zIndex
:
999
,
borderRadius
:
'16rpx'
,
transition
:
'all 0.3s ease'
}
}
// Xingmalabnotimepop 组件配置
export
const
xingmalabNoTimeConfig
=
{
// 图片资源路径配置
images
:
{
// 弹窗背景图片
background
:
`XingmaLabPop/
${
version
}
/XingmaLabNoTimePopBg.png`
,
// 按钮图片
button
:
`XingmaLabPop/
${
version
}
/XingmaLabNoTimePopBtn.png`
},
// 弹窗尺寸配置
dimensions
:
{
width
:
750
,
height
:
1624
,
background
:
{
width
:
618
,
height
:
460
,
image
:
`XingmaLabPop/
${
version
}
/XingmaLabNoTimePopBg.png`
},
button
:
{
width
:
466
,
height
:
97
,
left
:
76
,
top
:
312
,
image
:
`XingmaLabPop/
${
version
}
/XingmaLabNoTimePopBtn.png`
}
},
// 文案配置
texts
:
{
defaultTitle
:
'暂无时间'
},
// 样式配置
styles
:
{
zIndex
:
999
,
borderRadius
:
'16rpx'
,
transition
:
'all 0.3s ease'
}
}
// 获取完整图片URL
export
const
getImageUrl
=
(
imagePath
)
=>
{
return
`
${
imagePath
}
`
}
// 获取所有图片配置
export
const
getAllImages
=
()
=>
{
return
{
confirm
:
xingmalabConfirmConfig
.
images
,
noTime
:
xingmalabNoTimeConfig
.
images
}
}
// 获取尺寸配置
export
const
getDimensions
=
(
type
=
'confirm'
)
=>
{
return
type
===
'noTime'
?
xingmalabNoTimeConfig
.
dimensions
:
xingmalabConfirmConfig
.
dimensions
}
// 获取样式配置
export
const
getStyles
=
(
type
=
'confirm'
)
=>
{
return
type
===
'noTime'
?
xingmalabNoTimeConfig
.
styles
:
xingmalabConfirmConfig
.
styles
}
// 获取指定组件的配置
export
const
getComponentConfig
=
(
type
=
'confirm'
)
=>
{
return
type
===
'noTime'
?
xingmalabNoTimeConfig
:
xingmalabConfirmConfig
}
// 获取指定组件的图片配置
export
const
getComponentImages
=
(
type
=
'confirm'
)
=>
{
return
type
===
'noTime'
?
xingmalabNoTimeConfig
.
images
:
xingmalabConfirmConfig
.
images
}
// 获取指定组件的完整图片URL
export
const
getComponentImageUrl
=
(
type
=
'confirm'
,
imageKey
)
=>
{
const
images
=
getComponentImages
(
type
)
return
images
[
imageKey
]
?
`
${
getImageUrl
(
images
[
imageKey
])}
`
:
''
}
// 获取指定组件的所有图片URL
export
const
getAllComponentImageUrls
=
(
type
=
'confirm'
)
=>
{
const
images
=
getComponentImages
(
type
)
const
result
=
{}
Object
.
keys
(
images
).
forEach
(
key
=>
{
result
[
key
]
=
getComponentImageUrl
(
type
,
key
)
})
return
result
}
components/xingmaLab/example.vue
0 → 100644
View file @
fc9295c6
<
template
>
<view
class=
"example-page"
>
<view
class=
"header"
>
<text
class=
"title"
>
XingmaLab 弹窗组件示例
</text>
</view>
<view
class=
"content"
>
<view
class=
"section"
>
<text
class=
"section-title"
>
确认弹窗组件
</text>
<view
class=
"button-group"
>
<button
class=
"btn btn-primary"
@
click=
"showBasicConfirm = true"
>
基础确认弹窗
</button>
<button
class=
"btn btn-secondary"
@
click=
"showCustomConfirm = true"
>
自定义文本弹窗
</button>
<button
class=
"btn btn-warning"
@
click=
"showDeleteConfirm = true"
>
删除确认弹窗
</button>
</view>
</view>
<view
class=
"section"
>
<text
class=
"section-title"
>
无时间弹窗组件
</text>
<view
class=
"button-group"
>
<button
class=
"btn btn-info"
@
click=
"showNoTime = true"
>
显示无时间弹窗
</button>
<button
class=
"btn btn-success"
@
click=
"showCustomNoTime = true"
>
自定义标题弹窗
</button>
</view>
</view>
</view>
<!-- 基础确认弹窗 -->
<Xingmalabconfirmpop
:visible=
"showBasicConfirm"
@
confirm=
"handleBasicConfirm"
@
cancel=
"handleBasicCancel"
@
close=
"showBasicConfirm = false"
/>
<!-- 自定义文本弹窗 -->
<Xingmalabconfirmpop
:visible=
"showCustomConfirm"
title=
"自定义操作"
confirm-text=
"确定执行"
cancel-text=
"暂不执行"
@
confirm=
"handleCustomConfirm"
@
cancel=
"handleCustomCancel"
@
close=
"showCustomConfirm = false"
/>
<!-- 删除确认弹窗 -->
<Xingmalabconfirmpop
:visible=
"showDeleteConfirm"
title=
"删除确认"
confirm-text=
"删除"
cancel-text=
"取消"
@
confirm=
"handleDeleteConfirm"
@
cancel=
"handleDeleteCancel"
@
close=
"showDeleteConfirm = false"
/>
<!-- 无时间弹窗 -->
<Xingmalabnotimepop
:visible=
"showNoTime"
@
button-click=
"handleNoTimeButtonClick"
@
close=
"showNoTime = false"
/>
<!-- 自定义标题无时间弹窗 -->
<Xingmalabnotimepop
:visible=
"showCustomNoTime"
title=
"系统繁忙"
@
button-click=
"handleCustomNoTimeButtonClick"
@
close=
"showCustomNoTime = false"
/>
</view>
</
template
>
<
script
setup
>
import
{
ref
}
from
'vue'
import
Xingmalabconfirmpop
from
'./Xingmalabconfirmpop.vue'
import
Xingmalabnotimepop
from
'./Xingmalabnotimepop.vue'
// 确认弹窗显示状态
const
showBasicConfirm
=
ref
(
false
)
const
showCustomConfirm
=
ref
(
false
)
const
showDeleteConfirm
=
ref
(
false
)
// 无时间弹窗显示状态
const
showNoTime
=
ref
(
false
)
const
showCustomNoTime
=
ref
(
false
)
// 基础确认弹窗事件处理
const
handleBasicConfirm
=
()
=>
{
uni
.
showToast
({
title
:
'用户点击了确认'
,
icon
:
'success'
})
showBasicConfirm
.
value
=
false
}
const
handleBasicCancel
=
()
=>
{
uni
.
showToast
({
title
:
'用户点击了取消'
,
icon
:
'none'
})
showBasicConfirm
.
value
=
false
}
// 自定义文本弹窗事件处理
const
handleCustomConfirm
=
()
=>
{
uni
.
showToast
({
title
:
'执行自定义操作'
,
icon
:
'success'
})
showCustomConfirm
.
value
=
false
}
const
handleCustomCancel
=
()
=>
{
uni
.
showToast
({
title
:
'暂不执行操作'
,
icon
:
'none'
})
showCustomConfirm
.
value
=
false
}
// 删除确认弹窗事件处理
const
handleDeleteConfirm
=
()
=>
{
uni
.
showModal
({
title
:
'提示'
,
content
:
'确定要删除这个项目吗?'
,
success
:
(
res
)
=>
{
if
(
res
.
confirm
)
{
uni
.
showToast
({
title
:
'删除成功'
,
icon
:
'success'
})
}
}
})
showDeleteConfirm
.
value
=
false
}
const
handleDeleteCancel
=
()
=>
{
uni
.
showToast
({
title
:
'取消删除'
,
icon
:
'none'
})
showDeleteConfirm
.
value
=
false
}
// 无时间弹窗事件处理
const
handleNoTimeButtonClick
=
()
=>
{
uni
.
showToast
({
title
:
'用户点击了按钮'
,
icon
:
'success'
})
showNoTime
.
value
=
false
}
const
handleCustomNoTimeButtonClick
=
()
=>
{
uni
.
showToast
({
title
:
'系统繁忙,请稍后再试'
,
icon
:
'none'
})
showCustomNoTime
.
value
=
false
}
</
script
>
<
style
lang=
"less"
scoped
>
.example-page {
padding: 40rpx;
background-color: #f5f5f5;
min-height: 100vh;
}
.header {
text-align: center;
margin-bottom: 60rpx;
.title {
font-size: 48rpx;
font-weight: bold;
color: #333;
}
}
.content {
.section {
margin-bottom: 60rpx;
.section-title {
display: block;
font-size: 36rpx;
font-weight: 600;
color: #333;
margin-bottom: 30rpx;
padding-left: 20rpx;
border-left: 8rpx solid #007aff;
}
.button-group {
display: flex;
flex-direction: column;
gap: 30rpx;
.btn {
padding: 30rpx;
border-radius: 16rpx;
border: none;
font-size: 32rpx;
font-weight: 500;
&.btn-primary {
background-color: #007aff;
color: white;
}
&.btn-secondary {
background-color: #34c759;
color: white;
}
&.btn-warning {
background-color: #ff3b30;
color: white;
}
&.btn-info {
background-color: #5ac8fa;
color: white;
}
&.btn-success {
background-color: #4cd964;
color: white;
}
&:active {
opacity: 0.8;
}
}
}
}
}
</
style
>
components/xingmaLab/xingmalabImages.js
0 → 100644
View file @
fc9295c6
const
version
=
'v1'
// XingmaLab 弹窗组件图片资源常量
export
const
XINGMALAB_IMAGES
=
{
// 确认弹窗相关图片
CONFIRM
:
{
BG
:
`XingmaLabPop/
${
version
}
/XingmaLabConfirmPopBg.png`
,
CONFIRM_BTN
:
`XingmaLabPop/
${
version
}
/XingmaLabConfirmPopConfirmBtn.png`
,
CANCEL_BTN
:
`XingmaLabPop/
${
version
}
/XingmaLabCancelBtn.png`
},
// 无时间弹窗相关图片
NO_TIME
:
{
BG
:
`XingmaLabPop/
${
version
}
/XingmaLabNoTimePopBg.png`
,
BTN
:
`XingmaLabPop/
${
version
}
/XingmaLabNoTimePopBtn.png`
}
}
mock/home.json
View file @
fc9295c6
{
"contentImgList"
:
[{
"contentImgList"
:
[
{
"videoUrl"
:
"https://course.feihe.com/momclub-picture/homepage/4-0%E5%AE%98%E7%BD%91%E8%A7%86%E9%A2%91.mp4"
,
"_style"
:
"width:311rpx;height: 324rpx;left: 40rpx;top: 0;"
,
"link"
:
"www.baidu.com"
,
"bgUrl"
:
"homepage/content_1.png"
},
{
},
{
"videoUrl"
:
"https://course.feihe.com/momclub-picture/homepage/%E9%A6%96%E9%A1%B5_2%E9%A3%9E%E9%B9%A4%E8%BF%9E%E7%BB%AD%E4%BA%94%E5%B9%B4%E5%A5%B6%E7%B2%89%E7%AC%AC%E4%B8%80.mp4"
,
"_style"
:
"width:263rpx;height: 324rpx;right: 40rpx;top: 400rpx;"
,
"link"
:
"www.baidu.com"
,
"bgUrl"
:
"homepage/content_2.png"
},
{
},
{
"videoUrl"
:
"https://course.feihe.com/momclub-picture/homepage/%E9%A6%96%E9%A1%B5_3%E3%80%909%E6%9C%8827%E6%97%A5%E3%80%91%E9%A3%9E%E9%B9%A4_%E4%B8%96%E7%95%8C%E6%97%85%E6%B8%B8%E6%97%A5.mp4"
,
"_style"
:
"width:418rpx;height: 345rpx;left: 40rpx;top: 750rpx;"
,
"link"
:
"www.baidu.com"
,
"bgUrl"
:
"homepage/content_3.png"
},
{
},
{
"_style"
:
"width:263rpx;height: 324rpx;right: 40rpx;top: 1120rpx;"
,
"link"
:
{
"extra"
:
{},
...
...
@@ -22,12 +26,14 @@
"url"
:
"https://mp.weixin.qq.com/s/HhBF5h8xX8zOrthsy2-Y-A"
},
"bgUrl"
:
"homepage/content_4.png"
}],
}
],
"toolList"
:
{
"maintitle"
:
"工具推荐"
,
"jtIcon"
:
"homepage/tool_jt.png"
,
"subtitle"
:
"更多妈妈都在用,告别手忙脚乱,助你轻松带娃!"
,
"tools"
:
[{
"tools"
:
[
{
"icon"
:
"homepage/tool_icon_2.png"
,
"link"
:
{
"extra"
:
{},
...
...
@@ -37,7 +43,8 @@
"context"
:
"一键更新喂养记录"
,
"type"
:
1
,
"title"
:
"喂养工具"
},
{
},
{
"icon"
:
"homepage/tool_icon_3.png"
,
"link"
:
{
"extra"
:
{},
...
...
@@ -47,7 +54,8 @@
"context"
:
"孕周检查准时告知"
,
"type"
:
1
,
"title"
:
"产检提醒"
},
{
},
{
"icon"
:
"homepage/tool_icon_4.png"
,
"link"
:
{
"extra"
:
{},
...
...
@@ -57,7 +65,8 @@
"context"
:
"发育偏离预警早报"
,
"type"
:
1
,
"title"
:
"宝宝生长测评"
},
{
},
{
"icon"
:
"homepage/tool_icon_6.png"
,
"link"
:
{
"extra"
:
{},
...
...
@@ -67,7 +76,8 @@
"context"
:
"测体质选奶粉"
,
"type"
:
1
,
"title"
:
"体质测试"
},
{
},
{
"icon"
:
"homepage/tool_icon_1.png"
,
"link"
:
{
"extra"
:
{},
...
...
@@ -77,7 +87,8 @@
"context"
:
"AI生成吉利好名"
,
"type"
:
1
,
"title"
:
"星妈起名"
}],
}
],
"bgUrl"
:
"homepage/toolBg.png"
},
"suggest"
:
{
...
...
@@ -86,7 +97,13 @@
"url"
:
"https://mom.feihe.com/expertsView?from=home"
}
},
"channelTabList"
:
[
"凯叔讲故事"
,
"品格培养"
,
"知识科普"
,
"睡眠作息"
,
"宝贝喂养"
],
"channelTabList"
:
[
"凯叔讲故事"
,
"品格培养"
,
"知识科普"
,
"睡眠作息"
,
"宝贝喂养"
],
"popupImageObj"
:
{
"btnName"
:
"立即寻宝"
,
"jumpType"
:
1
,
...
...
@@ -102,7 +119,8 @@
}
},
"channelTabListMianTitle"
:
"有声频道"
,
"swiperList"
:
[{
"swiperList"
:
[
{
"img"
:
"homepage/homeSwiper/V1/7.jpg"
,
"link"
:
{
"extra"
:
{},
...
...
@@ -112,31 +130,23 @@
"type"
:
1
,
"title"
:
"北纬47°鲜活溯源之旅"
,
"url"
:
"homepage/homeSwiper/V1/7.jpg"
},
{
},
{
"videoUrl"
:
"homepage/homeSwiper/V1/8.mp4"
,
"link"
:
{},
"title"
:
"先是自己再是妈妈"
,
"url"
:
"homepage/homeSwiper/V1/8.png"
},
{
},
{
"videoUrl"
:
"homepage/homeSwiper/V1/2.m4v"
,
"link"
:
{},
"title"
:
"成为妈妈更懂妈妈"
,
"url"
:
"homepage/homeSwiper/V1/2.png"
},
{
"img"
:
"homepage/homeSwiper/V1/28会员日.jpg"
,
"link"
:
{
"extra"
:
{
"envVersion"
:
"release"
,
"appId"
:
"wx4205ec55b793245e"
},
"type"
:
2
,
"url"
:
"/subPackages/shopMainList/topicNew/index?id=1001087"
},
"title"
:
"28会员日"
,
"url"
:
"homepage/homeSwiper/V1/28会员日.jpg"
}],
}
],
"childrenInfoList"
:
[
[{
[
{
"desc2"
:
"乙肝母婴传播可防可控,但“时间窗口”不容错过!"
,
"link"
:
{
"extra"
:
{},
...
...
@@ -146,7 +156,8 @@
"isNew"
:
false
,
"desc"
:
"新生儿出生后24小时必做!错过可能影响一生健康"
,
"bgUrl"
:
"homepage/children/childrenV1/1.jpg"
},
{
},
{
"desc2"
:
"家长通过科学抚触,不仅能激活宝宝大脑神经突触,还能为宝宝的认知力、自护力打下坚实基础。"
,
"link"
:
{
"extra"
:
{},
...
...
@@ -156,7 +167,8 @@
"isNew"
:
false
,
"desc"
:
"0-3岁宝宝触觉发育关键期,附按摩手法!"
,
"bgUrl"
:
"homepage/children/childrenV1/2.jpg"
},
{
},
{
"desc2"
:
"究竟是体质虚弱?生病了?还是缺乏某些营养元素呢?星妈会带你一次性搞懂宝宝出汗的秘密!"
,
"link"
:
{
"extra"
:
{},
...
...
@@ -166,16 +178,19 @@
"isNew"
:
false
,
"desc"
:
"宝宝满头汗vs全身湿!小心这4种疾病,正在偷走健康!"
,
"bgUrl"
:
"homepage/children/childrenV1/3.jpg"
}]
}
]
],
"vipConfigList"
:
[{
"vipConfigList"
:
[
{
"btnTitle"
:
"首注200元优惠券"
,
"subTitle"
:
"新人礼权益"
,
"level"
:
"注册会员"
,
"btnSubTitle"
:
"立即注册"
,
"grade"
:
"-1"
,
"bgUrl"
:
"homepage/cardbg1.png"
},
{
},
{
"btnTitle"
:
"三甲医生在线问诊"
,
"subTitle"
:
"免费问诊权益"
,
"btnSubTitle"
:
"立即了解"
,
...
...
@@ -189,7 +204,8 @@
"url"
:
"subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
},
"bgUrl"
:
"homepage/cardbg1.png"
},
{
},
{
"btnTitle"
:
"12类系列课程"
,
"subTitle"
:
"育儿课程权益"
,
"btnSubTitle"
:
"立即了解"
,
...
...
@@ -203,7 +219,8 @@
"url"
:
"subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
},
"bgUrl"
:
"homepage/cardbg1.png"
},
{
},
{
"btnTitle"
:
"12类系列课程"
,
"subTitle"
:
"育儿课程权益"
,
"btnSubTitle"
:
"立即了解"
,
...
...
@@ -217,7 +234,8 @@
"url"
:
"subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
},
"bgUrl"
:
"homepage/cardbg1.png"
},
{
},
{
"btnTitle"
:
"1分购、优惠券"
,
"subTitle"
:
"月月礼权益"
,
"btnSubTitle"
:
"立即了解"
,
...
...
@@ -231,7 +249,8 @@
"url"
:
"subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
},
"bgUrl"
:
"homepage/cardbg1.png"
},
{
},
{
"btnTitle"
:
"1分购、优惠券"
,
"subTitle"
:
"月月礼权益"
,
"btnSubTitle"
:
"立即了解"
,
...
...
@@ -245,9 +264,11 @@
"url"
:
"subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
},
"bgUrl"
:
"homepage/cardbg1.png"
}],
}
],
"changelInfoList"
:
[
[{
[
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -255,7 +276,8 @@
},
"desc"
:
"凯叔·金子美铃童诗:【藏好了吗】"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/1/1.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -263,7 +285,8 @@
},
"desc"
:
"凯叔·金子美铃童诗:【水和风和娃娃】"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/1/2.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -271,7 +294,8 @@
},
"desc"
:
"凯叔·金子美铃童诗:【羽绒被】"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/1/3.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -279,7 +303,8 @@
},
"desc"
:
"凯叔·金子美铃童诗:【知了的外衣】"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/1/4.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -287,7 +312,8 @@
},
"desc"
:
"凯叔·金子美铃童诗:【风】"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/1/5.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -295,8 +321,10 @@
},
"desc"
:
"凯叔·金子美铃童诗:【我和小鸟和铃铛】"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/1/6.jpg"
}],
[{
}
],
[
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -304,7 +332,8 @@
},
"desc"
:
"培养宝宝不虚荣的好品格:【红舞鞋】"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/2/1.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -312,7 +341,8 @@
},
"desc"
:
"【动物王国】教宝宝学会爱护东西:【谁是破坏王】"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/2/2.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -320,7 +350,8 @@
},
"desc"
:
"培养宝宝拒绝的勇气:【该说不,就说不】"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/2/3.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -328,7 +359,8 @@
},
"desc"
:
"培养宝宝专心的好习惯:【两个青年学棋】"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/2/4.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -336,7 +368,8 @@
},
"desc"
:
"培养宝宝坚持的好品格:【不怕挫折的渔夫】"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/2/5.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -344,8 +377,10 @@
},
"desc"
:
"培养宝宝的自制力:【一次只要一个】"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/2/6.jpg"
}],
[{
}
],
[
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -353,7 +388,8 @@
},
"desc"
:
"营养健康小知识:营养元素钙铁锌"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/3/1.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -361,7 +397,8 @@
},
"desc"
:
"宝宝指甲长倒刺是缺维生素吗?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/3/2.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -369,7 +406,8 @@
},
"desc"
:
"如何分辨宝宝是攒肚还是便秘?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/3/3.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -377,7 +415,8 @@
},
"desc"
:
"手足口疫苗有必要打吗?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/3/4.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -385,7 +424,8 @@
},
"desc"
:
"宝宝多大开始刷牙?一定不能晚于这个时间!"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/3/5.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -393,8 +433,10 @@
},
"desc"
:
"如何缓解0-6月宝宝肠绞痛?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/3/6.jpg"
}],
[{
}
],
[
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -402,7 +444,8 @@
},
"desc"
:
"如何拯救睡渣宝宝?培养自主入睡?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/4/1.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -410,7 +453,8 @@
},
"desc"
:
"开灯睡觉影响宝宝智力发育?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/4/2.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -418,7 +462,8 @@
},
"desc"
:
"宝宝都爱“投降式睡姿”?要纠正吗?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/4/3.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -426,7 +471,8 @@
},
"desc"
:
"娃睡得正香,要不要叫醒吃奶?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/4/4.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -434,7 +480,8 @@
},
"desc"
:
"宝宝总夜醒怎么办?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/4/5.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -442,8 +489,10 @@
},
"desc"
:
"宝宝每天睡多久合适?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/4/6.jpg"
}],
[{
}
],
[
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -451,7 +500,8 @@
},
"desc"
:
"宝宝夏日拉肚子该怎么办?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/5/1.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -459,7 +509,8 @@
},
"desc"
:
"给宝宝冲奶粉,冲稀点不上火,浓点更营养?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/5/2.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -467,7 +518,8 @@
},
"desc"
:
"怎样辨别奶粉中含有香精?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/5/3.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -475,7 +527,8 @@
},
"desc"
:
"怎样判断宝宝吃饱了没?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/5/4.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -483,7 +536,8 @@
},
"desc"
:
"奶粉颜色偏黄好?还是偏白好?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/5/5.jpg"
},
{
},
{
"link"
:
{
"extra"
:
{},
"type"
:
3
,
...
...
@@ -491,26 +545,33 @@
},
"desc"
:
"冲奶粉,不能用哪种水?"
,
"bgUrl"
:
"homepage/channel/soundChannelV1/5/6.jpg"
}]
}
]
],
"bottomLinkList"
:
[{
"bottomLinkList"
:
[
{
"_style"
:
"width:70rpx;height:109rpx;"
,
"link"
:
"www.baidu.com"
,
"bgUrl"
:
"homepage/iconwx.png"
},
{
},
{
"_style"
:
"width:95rpx;height:109rpx;"
,
"link"
:
"www.baidu.com"
,
"bgUrl"
:
"homepage/iconqw.png"
},
{
},
{
"_style"
:
"width:70rpx;height:109rpx;"
,
"link"
:
"www.baidu.com"
,
"bgUrl"
:
"homepage/iconsph.png"
},
{
},
{
"_style"
:
"width:88rpx;height:99rpx;"
,
"link"
:
"www.baidu.com"
,
"bgUrl"
:
"homepage/iconxhs.png"
}],
"vipCardList"
:
[{
}
],
"vipCardList"
:
[
{
"btnTitle"
:
"12类系列课程"
,
"subTitle"
:
"育儿课程权益"
,
"level"
:
"钻石会员"
,
...
...
@@ -524,7 +585,8 @@
"url"
:
"subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
},
"bgUrl"
:
"homepage/cardbg1.png"
},
{
},
{
"btnTitle"
:
""
,
"showCornerTxt"
:
""
,
"subTitle"
:
"来自万年黑土的健康食品"
,
...
...
@@ -539,7 +601,8 @@
"url"
:
"subPackages/shopMainList/topicNew/index?id=1000265&entrySource=xmh_wechatmp_home_recgoods"
},
"bgUrl"
:
"homepage/cardbg2.png"
},
{
},
{
"btnTitle"
:
""
,
"showCornerTxt"
:
""
,
"subTitle"
:
"专家文章、育儿知识、饮食知识"
,
...
...
@@ -551,20 +614,25 @@
"url"
:
"/pages/library/ContentLibrary"
},
"bgUrl"
:
"homepage/cardbg3.png"
}],
"qrInfoList"
:
[{
}
],
"qrInfoList"
:
[
{
"qrUrl"
:
"homepage/qrcode_gzh.png"
,
"title"
:
"公众号"
,
"desc"
:
"长按关注<span style:'color:#D3A358;'>星妈会</span>公众号,了解更多专业育儿资讯"
},
{
},
{
"qrUrl"
:
"homepage/qrcode_qw.png"
,
"title"
:
"企业微信"
,
"desc"
:
"长按添加<span style:'color:#D3A358;'>星妈管家</span>,享受专家问诊与社群福利活动"
},
{
},
{
"qrUrl"
:
"homepage/qrcode_sph.png"
,
"title"
:
"视频号"
,
"desc"
:
"扫码关注<span style:'color:#D3A358;'>星妈会</span>视频号,了解更多专业育儿资讯"
}],
}
],
"childrenInfoListMianTitle"
:
"育儿智库"
,
"expertTeam"
:
{
"maintitle"
:
"专家团"
,
...
...
mock/my.json
View file @
fc9295c6
...
...
@@ -313,6 +313,26 @@
],
"tool"
:
[
[
{
"link"
:
{
"extra"
:
{},
"type"
:
1
,
"url"
:
"/pages/xingmaLab/xingmaLab"
},
"title"
:
"星妈会Lab"
,
"desc"
:
"星妈会Lab"
,
"bgUrl"
:
"my/icon_xingma_lab1.png"
},
{
"link"
:
{
"extra"
:
{},
"type"
:
1
,
"url"
:
"/pages/naming/naming"
},
"title"
:
"星妈起名"
,
"desc"
:
"星妈起名"
,
"bgUrl"
:
"my/naming.png"
},
{
"link"
:
{
"extra"
:
{},
...
...
@@ -425,6 +445,15 @@
"脑发育"
],
"activeInfo"
:
[
{
"img"
:
"https://course.feihe.com/momclub-picture/my/vipAct090201.png"
,
"extra"
:
{
"envVersion"
:
"release"
,
"appId"
:
"wx4205ec55b793245e"
},
"type"
:
2
,
"url"
:
"/subPackages/shopMainProcess/product/index?productId=739634042657637394&skuId=739635029460743612"
},
{
"img"
:
"https://course.feihe.com/momclub-picture/my/activeImg0823.png"
,
"extra"
:
{
...
...
@@ -441,4 +470,4 @@
"母婴店"
]
}
}
\ No newline at end of file
}
\ No newline at end of file
pages.json
View file @
fc9295c6
...
...
@@ -51,6 +51,12 @@
"navigationStyle"
:
"custom"
}
},
{
"path"
:
"pages/xingmaLab/xingmaLab"
,
"style"
:
{
"navigationStyle"
:
"custom"
}
},
{
"path"
:
"pages/goodsDetail/goodsDetail"
,
"style"
:
{
...
...
@@ -163,17 +169,32 @@
}
},
{
"path"
:
"pages/testPage/testPage"
,
"style"
:
"path"
:
"pages/testPage/testPage"
,
"style"
:
{
"navigationBarTitleText"
:
""
}
},
{
"navigationBarTitleText"
:
""
"path"
:
"pages/thirdJumpMiddlePage/thirdJumpMiddlePage"
,
"style"
:
{
"navigationBarTitleText"
:
""
}
},
{
"path"
:
"pages/thirdJumpMiddlePage/thirdJumpMiddlePage"
,
"style"
:
"path"
:
"pages/XingmaLabDetailPage/XingmaLabDetailPage"
,
"style"
:
{
"navigationBarTitleText"
:
""
,
"navigationStyle"
:
"custom"
,
"enableShare"
:
true
,
"shareAppMessage"
:
true
,
"shareTimeline"
:
false
}
},
{
"navigationBarTitleText"
:
""
"path"
:
"pages/XingmaLabPublishPage/XingmaLabPublishPage"
,
"style"
:
{
"navigationBarTitleText"
:
""
,
"navigationStyle"
:
"custom"
}
}
],
...
...
pages/XingmaLabDetailPage/README.md
0 → 100644
View file @
fc9295c6
# 星妈实验室详情页面 (XingmaLabDetailPage)
## 概述
这是一个基于Vue 3 Composition API开发的星妈实验室详情页面组件,用于展示藏品详情、点赞和分享功能。
## 功能特性
-
**藏品展示**
:展示藏品图片、编号和标题
-
**动态时间**
:自动显示当前时间
-
**点赞功能**
:支持点赞/取消点赞状态切换
-
**分享功能**
:集成uni-app分享API
-
**响应式设计**
:支持不同屏幕尺寸的适配
-
**交互动画**
:包含淡入动画和悬停效果
## 文件结构
```
XingmaLabDetailPage/
├── XingmaLabDetailPage.vue # 主组件文件
├── XingmaLabDetailPage.less # 样式文件
├── config.js # 配置文件
└── README.md # 说明文档
```
## 使用方法
### 1. 基本使用
```
vue
<
template
>
<XingmaLabDetailPage
/>
</
template
>
<
script
setup
>
import
XingmaLabDetailPage
from
'@/pages/XingmaLabDetailPage/XingmaLabDetailPage.vue'
</
script
>
```
### 2. 功能说明
#### 藏品信息展示
-
藏品背景图片
-
藏品主图片
-
藏品编号(唯一标识)
-
藏品标题
#### 交互功能
-
**点赞按钮**
:点击切换点赞状态,显示相应提示
-
**分享按钮**
:调用uni-app分享功能
#### 时间显示
-
自动显示当前日期和地点
-
格式:YYYY-MM-DD 北京
## 配置说明
### 图片资源配置
在
`config.js`
中配置图片资源路径:
```
javascript
export
const
xingmaLabDetailConfig
=
{
baseUrl
:
'https://factory-walk.feihe.com'
,
images
:
{
background
:
'/farqbxzczytcami/images/XingmaLabDetailPage/XingmaLabDetailPageBg.png'
,
picBg
:
'/farqbxzczytcami/images/XingmaLabDetailPage/XingmaLabDetailPagePicBg.png'
,
pic
:
'/farqbxzczytcami/images/XingmaLabDetailPage/XingmaLabDetailPagePic.png'
,
// ... 其他图片配置
}
}
```
### 文案配置
```
javascript
texts
:
{
title
:
'快来用星妈会小程序'
,
collectionNumber
:
'唯一藏品编号:'
}
```
## 样式定制
### 主要样式类
-
`.xingmalabdetailpage`
: 主容器
-
`.xingmalabdetailpagebg`
: 背景图片
-
`.xingmalabdetailpagepic`
: 藏品主图片
-
`.xingmalabdetailpagepicbg`
: 图片背景框
-
`.xingmalabdetailpagebottomcon`
: 底部操作容器
-
`.xingmalabdetailpagebottomconlikebtn`
: 点赞按钮
-
`.xingmalabdetailpagebottomconsharebtn`
: 分享按钮
### 响应式断点
-
默认:750rpx 宽度(移动端)
-
响应式:小于750px时自动适配为100vw
### 动画效果
-
`fadeIn`
: 页面淡入动画
-
`slideInUp`
: 图片和底部容器从下往上滑入动画
-
点赞状态变化时的视觉反馈
## 交互功能
### 点赞功能
```
javascript
const
handleLikeClick
=
()
=>
{
isLiked
.
value
=
!
isLiked
.
value
// 显示点赞状态提示
uni
.
showToast
({
title
:
isLiked
.
value
?
'已点赞'
:
'取消点赞'
,
icon
:
'success'
})
}
```
### 分享功能
```
javascript
const
handleShareClick
=
()
=>
{
// 调用uni-app分享API
uni
.
showShareMenu
({
withShareTicket
:
true
,
menus
:
[
'shareAppMessage'
,
'shareTimeline'
]
})
}
```
## 开发规范
-
使用Vue 3 Composition API
-
遵循项目ESLint和Prettier规范
-
使用Less预处理器
-
支持uni-app跨平台开发
-
使用响应式数据管理状态
## 注意事项
1.
确保图片资源路径正确配置
2.
图片资源需要支持HTTPS协议
3.
组件使用绝对定位布局,注意父容器样式设置
4.
点赞状态会保存在组件内部,页面刷新后会重置
5.
时间显示基于客户端时间,确保设备时间准确
## 更新日志
-
v1.0.0: 初始版本,支持藏品展示、点赞和分享功能
-
支持动态资源管理和响应式设计
-
集成uni-app分享API
-
添加交互动画和状态反馈
pages/XingmaLabDetailPage/XingmaLabDetailPage.less
0 → 100644
View file @
fc9295c6
// 星妈实验室详情页面样式
.xingmalabdetailpage {
width: 750rpx;
height: calc(100vh - 218rpx);
left: 0rpx;
top: 0rpx;
overflow-y: auto;
position: absolute;
// 左上角头部区域 - 脱离滚动
.xingmalabdetailpageheader {
position: fixed;
top: 0;
left: 0;
width: 750rpx;
height: 200rpx;
z-index: 100;
display: flex;
align-items: center;
// justify-content: space-between;
padding: 80rpx 40rpx 30rpx 40rpx;
background-color: #fff;
box-sizing: border-box;
// 返回按钮
.xingmalabdetailpagebackbtn {
width: 20rpx;
height: 33rpx;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
// cursor: pointer;
z-index: 101;
margin-right: 35rpx;
}
// 用户信息
.xingmalabdetailpageuserinfo {
display: flex;
align-items: center;
gap: 10rpx;
// 头像
.xingmalabdetailpageavatar {
width: 66rpx;
height: 66rpx;
border-radius: 50%;
object-fit: contain;
background-color: #f8f9fa;
}
// 昵称
.xingmalabdetailpagenickname {
font-size: 28rpx;
font-weight: 600;
color: #1d1e25;
text-shadow: 0 2rpx 4rpx rgba(255, 255, 255, 0.8);
max-width: 300rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
.xingmalabdetailpagebg {
width: 750rpx;
height: 1842rpx;
left: 0rpx;
top: 0rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
// 文本和时间容器
.xingmalabdetailpagecontent {
width: 688rpx;
left: 31rpx;
top: 1232rpx;
position: absolute;
// 确保内容不被底部固定容器遮挡
z-index: 1;
}
.xingmalabdetailpagetext {
width: 100%;
min-height: 131rpx;
white-space: pre-wrap;
position: relative;
font-size: 32rpx;
line-height: 50rpx;
color: rgba(29, 30, 37, 1);
text-align: left;
word-wrap: break-word;
word-break: break-all;
// 移除固定高度,让内容自适应
height: auto;
display: block;
}
.xingmalabdetailpagepicbg {
width: 730rpx;
height: 1030rpx;
left: 10rpx;
top: 191rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.xingmalabdetailpagepic {
width: 688rpx;
height: 914rpx;
left: 31rpx;
top: 207rpx;
border-radius: 24rpx;
position: absolute;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
background-color: #f8f9fa;
}
.xingmalabdetailpagenum {
width: 348rpx;
height: 26rpx;
left: 207rpx;
top: 1144rpx;
position: absolute;
font-size: 28rpx;
line-height: 26rpx;
color: rgba(178, 124, 30, 1);
text-align: center;
}
.xingmalabdetailpagebottomcon {
width: 750rpx;
height: 218rpx;
left: 0rpx;
bottom: 0rpx;
background-color: #fff;
position: fixed;
.xingmalabdetailpagebottomconbg {
width: 750rpx;
height: 218rpx;
left: 0rpx;
top: 0rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.xingmalabdetailpagebottomconlikebtn {
width: 119rpx;
height: 44rpx;
left: 135rpx;
top: 56rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
transition: opacity 0.3s ease;
&:hover {
opacity: 0.8;
}
}
.xingmalabdetailpagebottomconsharebtn {
width: 121rpx;
height: 42rpx;
left: 498rpx;
top: 58rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
border: none;
padding: 0;
margin: 0;
line-height: 1;
font-size: 0;
color: transparent;
background-color: transparent !important;
transition: opacity 0.3s ease;
// &:hover {
// opacity: 0.8;
// }
&::after {
border: none !important;
}
}
}
.xingmalabdetailpagetime {
width: 203rpx;
height: 23rpx;
margin-top: 20rpx;
position: relative;
font-size: 24rpx;
line-height: 23rpx;
color: rgba(111, 109, 103, 1);
display: block;
}
}
// 手机号授权按钮样式
.phone-auth-btn-cover {
background: transparent !important;
border: none !important;
padding: 0 !important;
margin: 0 !important;
line-height: 1 !important;
font-size: 0 !important;
color: transparent !important;
&::after {
border: none !important;
}
}
// 授权覆盖层样式
.auth-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
.auth-like-btn {
position: absolute;
width: 119rpx;
height: 44rpx;
left: 135rpx;
top: 56rpx;
}
.auth-share-btn {
position: absolute;
width: 121rpx;
height: 42rpx;
left: 498rpx;
top: 58rpx;
}
}
pages/XingmaLabDetailPage/XingmaLabDetailPage.vue
0 → 100644
View file @
fc9295c6
<
template
>
<view
class=
"xingmalabdetailpage modal_center"
>
<!--
<span
class=
"xingmalabdetailpagebg"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.background)})` }">
</span>
-->
<!-- 左上角头部区域 - 脱离滚动 -->
<div
class=
"xingmalabdetailpageheader"
>
<!-- 返回按钮 -->
<span
class=
"xingmalabdetailpagebackbtn"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.backBtn)})` }"
@click="handleGoBack">
</span>
<!-- 用户信息 -->
<div
class=
"xingmalabdetailpageuserinfo"
>
<image
v-if=
"detailData.avatar"
:src=
"detailData.avatar"
class=
"xingmalabdetailpageavatar"
mode=
"aspectFit"
/>
<span
class=
"xingmalabdetailpagenickname"
>
{{
detailData
.
nickname
||
'星妈用户'
}}
</span>
</div>
</div>
<!-- 文本和时间容器 -->
<div
class=
"xingmalabdetailpagecontent"
>
<span
class=
"xingmalabdetailpagetext"
>
{{
detailData
.
content
||
config
.
texts
.
title
}}
</span>
<span
class=
"xingmalabdetailpagetime"
v-if=
"detailData.owner && detailData.gmtCreate"
>
{{
formatTime
(
detailData
.
gmtCreate
)
}}
</span>
</div>
<span
class=
"xingmalabdetailpagepicbg"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.picBg)})` }">
</span>
<image
v-if=
"detailData.imgUrl"
:src=
"detailData.imgUrl"
class=
"xingmalabdetailpagepic"
mode=
"aspectFit"
/>
<span
class=
"xingmalabdetailpagenum"
>
{{
config
.
texts
.
collectionNumber
}}{{
detailData
.
bizNo
||
collectionNumber
}}
</span>
<div
class=
"xingmalabdetailpagebottomcon"
v-if=
"detailData.state === 1"
>
<span
class=
"xingmalabdetailpagebottomconbg"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.bottomConBg)})` }">
</span>
<!-- 收藏按钮 -->
<span
class=
"xingmalabdetailpagebottomconlikebtn"
:class=
"
{ liked: detailData.collection }"
:style="{ backgroundImage: `url(${$baseUrl}${getImageUrl(detailData.collection ? config.images.bottomConLikeBtnSel : config.images.bottomConLikeBtn)})` }"
@click="handleLikeClick">
</span>
<!-- 分享按钮 -->
<button
open-type=
"share"
class=
"xingmalabdetailpagebottomconsharebtn"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.bottomConShareBtn)})` }"
@click="handleShareClick">
</button>
<!-- 未登录时覆盖的授权按钮层 -->
<div
v-if=
"homeStore && !homeStore.isLogin"
class=
"auth-overlay"
>
<!-- 收藏按钮授权覆盖 -->
<button
open-type=
"getPhoneNumber"
@
getphonenumber=
"(e) => onGetPhoneNumber(e, 'like')"
class=
"auth-like-btn phone-auth-btn-cover"
></button>
<!-- 分享按钮授权覆盖 - 移除这个,让分享按钮正常工作 -->
</div>
</div>
</view>
</
template
>
<
script
setup
>
import
{
ref
,
onMounted
,
computed
,
onUnmounted
}
from
'vue'
import
{
xingmaLabDetailConfig
,
getImageUrl
}
from
'./config.js'
import
{
fetchRecordDetail
,
fetchFavoriteAdd
,
fetchFavoriteRemove
}
from
'@/api/xingmaLab.js'
import
{
useHomeStore
}
from
'@/stores/home.js'
import
{
useUserStore
}
from
'@/stores/user.js'
import
md
from
'../../md'
;
// 组件名称
defineOptions
({
name
:
'XingmaLabDetailPage'
})
// 响应式数据
const
collectionNumber
=
ref
(
'123456789'
)
const
recordId
=
ref
(
''
)
// 添加记录ID的响应式变量
const
detailData
=
ref
({
content
:
''
,
gmtCreate
:
''
,
owner
:
false
,
imgUrl
:
''
,
nickname
:
''
,
avatar
:
''
,
collection
:
false
,
bizNo
:
''
,
state
:
null
})
// 配置对象
const
config
=
xingmaLabDetailConfig
// 格式化时间
const
formatTime
=
(
timeStr
)
=>
{
if
(
!
timeStr
)
return
''
const
date
=
new
Date
(
timeStr
)
const
year
=
date
.
getFullYear
()
const
month
=
String
(
date
.
getMonth
()
+
1
).
padStart
(
2
,
'0'
)
const
day
=
String
(
date
.
getDate
()).
padStart
(
2
,
'0'
)
return
`
${
year
}
-
${
month
}
-
${
day
}
`
}
// 同步收藏状态到上一页
const
syncCollectionStatusToPrevPage
=
()
=>
{
const
pages
=
getCurrentPages
()
if
(
pages
.
length
>
1
)
{
let
prevPage
=
pages
[
pages
.
length
-
2
]
prevPage
.
setData
({
isFavorite
:
detailData
.
value
.
collection
?
1
:
-
1
})
console
.
log
(
'✅ 收藏状态已同步到上一页:'
,
detailData
.
value
.
collection
?
1
:
-
1
)
}
}
// 获取详情数据
const
fetchDetailData
=
async
(
id
)
=>
{
try
{
uni
.
showLoading
({
title
:
'加载中...'
,
mask
:
true
})
const
result
=
await
fetchRecordDetail
({
id
})
if
(
result
.
success
)
{
detailData
.
value
=
result
.
data
recordId
.
value
=
id
// 保存记录ID
console
.
log
(
'✅ 详情数据获取成功:'
,
detailData
.
value
)
// 初始化时同步收藏状态到上一页
syncCollectionStatusToPrevPage
()
}
else
{
throw
new
Error
(
result
.
message
||
'获取详情失败'
)
}
}
catch
(
error
)
{
console
.
error
(
'❌ 获取详情失败:'
,
error
)
uni
.
showToast
({
title
:
error
.
message
||
'获取详情失败'
,
icon
:
'none'
})
}
finally
{
uni
.
hideLoading
()
}
}
// 获取 stores
const
homeStore
=
useHomeStore
()
const
userStore
=
useUserStore
()
// 手机号授权回调
const
onGetPhoneNumber
=
(
e
,
action
)
=>
{
if
(
e
.
detail
.
errMsg
!==
'getPhoneNumber:ok'
)
{
uni
.
showToast
({
title
:
'请授权使用手机号'
,
icon
:
'none'
,
});
return
;
}
console
.
log
(
'detail'
,
e
.
detail
,
'action:'
,
action
);
// 调用手机号授权回调
userStore
.
phoneCallback
(
e
.
detail
).
then
(()
=>
{
// 授权成功后,根据点击的按钮执行相应功能
if
(
action
===
'like'
)
{
handleLikeClick
();
}
else
if
(
action
===
'share'
)
{
handleShareClick
();
}
});
}
// 方法
const
handleLikeClick
=
async
()
=>
{
//TODO:埋点
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"星妈lab-藏品详情页"
,
componentName
:
"藏品详情"
,
componentContent
:
"收藏"
});
try
{
const
recordId
=
detailData
.
value
.
id
if
(
!
recordId
)
{
uni
.
showToast
({
title
:
'记录ID不存在'
,
icon
:
'none'
})
return
}
if
(
detailData
.
value
.
collection
)
{
// 取消收藏
const
result
=
await
fetchFavoriteRemove
({
relationId
:
recordId
})
if
(
result
.
success
)
{
detailData
.
value
.
collection
=
false
// 更新时同步收藏状态到上一页
syncCollectionStatusToPrevPage
()
uni
.
showToast
({
title
:
'已取消收藏'
,
icon
:
'none'
})
}
else
{
throw
new
Error
(
result
.
message
||
'取消收藏失败'
)
}
}
else
{
// 添加收藏
const
result
=
await
fetchFavoriteAdd
({
relationId
:
recordId
})
if
(
result
.
success
)
{
detailData
.
value
.
collection
=
true
// 更新时同步收藏状态到上一页
syncCollectionStatusToPrevPage
()
uni
.
showToast
({
title
:
'收藏成功'
,
icon
:
'none'
})
}
else
{
throw
new
Error
(
result
.
message
||
'收藏失败'
)
}
}
}
catch
(
error
)
{
console
.
error
(
'收藏操作失败:'
,
error
)
uni
.
showToast
({
title
:
error
.
message
||
'操作失败,请重试'
,
icon
:
'none'
})
}
}
const
handleShareClick
=
()
=>
{
// 使用 open-type="share" 时,点击事件可以为空
// 分享内容通过页面配置自动设置
console
.
log
(
'分享按钮被点击'
)
//TODO:埋点
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"星妈lab-藏品详情页"
,
componentName
:
"藏品详情"
,
componentContent
:
"分享"
});
// 手动触发分享(如果需要的话)
// uni.showShareMenu({
// withShareTicket: true,
// menus: ['shareAppMessage'] // 仅分享给好友,禁用朋友圈
// })
}
// 返回上一页
const
handleGoBack
=
()
=>
{
// 检查是否有上一页
const
pages
=
getCurrentPages
()
console
.
log
(
'pages'
,
pages
)
if
(
pages
.
length
>
1
)
{
// 有上一页,直接返回上一页(收藏状态已在更新时同步)
uni
.
navigateBack
({
delta
:
1
})
}
else
{
// 没有上一页,跳转到星妈实验室页面,并传递index参数
uni
.
redirectTo
({
url
:
`/pages/xingmaLab/xingmaLab`
})
}
}
// 生命周期
onMounted
(
async
(
options
)
=>
{
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab-藏品详情页"
,
componentName
:
"藏品详情"
,
componentContent
:
"收藏"
});
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab-藏品详情页"
,
componentName
:
"藏品详情"
,
componentContent
:
"分享"
});
// 调用 home 接口获取登录状态
await
homeStore
.
loadHomeInfo
()
// 获取页面跳转参数中的 id 和 index
const
pages
=
getCurrentPages
()
const
currentPage
=
pages
[
pages
.
length
-
1
]
const
id
=
currentPage
.
options
?.
id
||
''
if
(
id
)
{
console
.
log
(
'🔍 获取到页面参数 id:'
,
id
)
recordId
.
value
=
id
// 立即保存ID,确保分享时能获取到
await
fetchDetailData
(
id
)
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab-藏品详情页"
,
componentName
:
"藏品详情"
,
componentContent
:
"藏品详情页+"
+
detailData
.
value
.
content
});
}
else
{
console
.
warn
(
'⚠️ 未获取到页面参数 id'
,
options
,
currentPage
.
options
)
// uni.showToast({
// title: '参数错误',
// icon: 'none'
// })
// uni.redirectTo({
// url: `/pages/xingmaLab/xingmaLab`
// })
}
uni
.
hideShareMenu
({
menus
:
[
'shareTimeline'
]
})
// 启用分享菜单(仅限分享给好友,禁用朋友圈)
uni
.
showShareMenu
({
withShareTicket
:
true
,
menus
:
[
'shareAppMessage'
]
})
})
// 定义分享函数
const
getShareData
=
()
=>
{
const
shareImage
=
detailData
.
value
.
imgUrl
||
''
const
shareContent
=
detailData
.
value
.
content
||
''
const
currentRecordId
=
recordId
.
value
||
detailData
.
value
.
id
||
''
// 截取分享文案,超出字数显示省略号
const
maxLength
=
50
const
truncatedContent
=
shareContent
.
length
>
maxLength
?
shareContent
.
substring
(
0
,
maxLength
)
+
'...'
:
shareContent
console
.
log
(
'分享参数:'
,
{
title
:
truncatedContent
,
imageUrl
:
shareImage
,
path
:
`/pages/XingmaLabDetailPage/XingmaLabDetailPage?id=
${
currentRecordId
}
`
,
recordId
:
currentRecordId
,
detailDataId
:
detailData
.
value
.
id
})
return
{
title
:
truncatedContent
,
imageUrl
:
shareImage
,
path
:
`/pages/XingmaLabDetailPage/XingmaLabDetailPage?id=
${
currentRecordId
}
`
}
}
// 暴露给 Options API 使用
defineExpose
({
getShareData
})
</
script
>
<
script
>
// 微信小程序分享配置 - 使用 Options API
export
default
{
// 自定义分享内容
onShareAppMessage
()
{
console
.
log
(
'onShareAppMessage 被调用'
)
// 获取当前页面的数据
const
pages
=
getCurrentPages
()
const
currentPage
=
pages
[
pages
.
length
-
1
]
const
options
=
currentPage
.
options
||
{}
const
id
=
options
.
id
||
''
// 获取页面实例
const
pageInstance
=
currentPage
.
$vm
if
(
pageInstance
&&
pageInstance
.
getShareData
)
{
return
pageInstance
.
getShareData
()
}
// 如果无法获取页面实例,返回默认分享内容
return
{
title
:
''
,
path
:
`/pages/XingmaLabDetailPage/XingmaLabDetailPage?id=
${
id
}
`
,
imageUrl
:
''
}
},
// 朋友圈分享已禁用
// onShareTimeline() {
// console.log('onShareTimeline 被调用')
// // 朋友圈分享功能已禁用
// return null
// }
}
</
script
>
<
style
lang=
"less"
scoped
>
@import './XingmaLabDetailPage.less';
</
style
>
pages/XingmaLabDetailPage/config.js
0 → 100644
View file @
fc9295c6
const
version
=
'v1'
// 星妈实验室详情页面配置
export
const
xingmaLabDetailConfig
=
{
// 图片资源路径配置
images
:
{
// 背景图片
background
:
`XingmaLabDetailPage/
${
version
}
/XingmaLabDetailPageBg.png`
,
// 图片背景
picBg
:
`XingmaLabDetailPage/
${
version
}
/XingmaLabDetailPagePicBg.png`
,
// 主图片
pic
:
`XingmaLabDetailPage/
${
version
}
/XingmaLabDetailPagePic.png`
,
// 底部容器背景
bottomConBg
:
`XingmaLabDetailPage/
${
version
}
/XingmaLabDetailPageBottomConBg.png`
,
// 收藏按钮
bottomConLikeBtn
:
`XingmaLabDetailPage/
${
version
}
/XingmaLabDetailPageBottomConLikeBtn.png`
,
// 已收藏按钮
bottomConLikeBtnSel
:
`XingmaLabDetailPage/
${
version
}
/XingmaLabDetailPageBottomConLikeBtnSel.png`
,
// 分享按钮
bottomConShareBtn
:
`XingmaLabDetailPage/
${
version
}
/XingmaLabDetailPageBottomConShareBtn.png`
,
// 返回按钮
backBtn
:
`XingmaLabDetailPage/
${
version
}
/XingmaLabDetailPageBackBtn.png`
},
// 文案配置
texts
:
{
title
:
'快来用星妈会小程序'
,
collectionNumber
:
'唯一藏品编号:'
},
// 页面配置
page
:
{
width
:
750
,
height
:
1624
}
}
// 获取完整图片URL
export
const
getImageUrl
=
(
imagePath
)
=>
{
return
`
${
imagePath
}
`
}
// 获取页面尺寸配置
export
const
getPageConfig
=
()
=>
{
return
xingmaLabDetailConfig
.
page
}
pages/XingmaLabPublishPage/CHANGELOG.md
0 → 100644
View file @
fc9295c6
# 星妈实验室发布页面更新日志
## 版本 1.1.0 - 2024-01-XX
### 新增功能
#### 1. 藏品图片上传功能
-
✅ 支持单张图片上传(限制1张)
-
✅ 固定宽度显示,不限制高度比例
-
✅ 文件大小限制(可配置,默认10MB)
-
✅ 支持格式:jpg、png、jpeg
-
✅ 点击上传区域拉起相机/相册选择器
-
✅ 超过大小限制时显示友好提示:"照片太大啦,换一张试试吧~"
#### 2. 重新上传功能
-
✅ 已上传图片右下角显示"重新上传"按钮
-
✅ 点击重新拉起相机/相册图库
-
✅ 支持jpg/png/jpeg格式选择
-
✅ 上传中状态显示
#### 3. 藏品文案介绍
-
✅ 最多输入1000字限制
-
✅ 点击拉起输入键盘
-
✅ 纯文本输入,不支持富文本
-
✅ 实时字数统计显示
-
✅ 达到字数上限时提示:"字数已达上限"
#### 4. 发布按钮交互优化
-
✅ 首次发布用户自动拉起微信头像昵称授权
-
✅ 已有头像昵称信息用户直接进入确认弹窗
-
✅ 授权拒绝时停留当前页面,再次点击重新拉起授权
-
✅ 确认弹窗显示上传图片和文案内容
-
✅ 后端校验发布次数限制
-
✅ 发布成功后显示随机成功文案
### 技术改进
#### 状态管理
-
✅ 完善的三状态管理:未选择、选择、成功
-
✅ 响应式数据绑定
-
✅ 计算属性优化
#### 用户体验
-
✅ 完善的错误处理和提示
-
✅ 加载状态显示
-
✅ 友好的交互反馈
-
✅ 响应式布局适配
#### 代码质量
-
✅ 遵循Vue 3 Composition API规范
-
✅ 模块化配置管理
-
✅ 完善的注释和文档
-
✅ 保持原有样式格局不变
### 配置项
```
javascript
// 图片上传配置
upload
:
{
maxSize
:
10
*
1024
*
1024
,
// 10MB
maxSizeText
:
'照片太大啦,换一张试试吧~'
,
maxWords
:
1000
,
maxWordsText
:
'字数已达上限'
,
allowedTypes
:
[
'jpg'
,
'png'
,
'jpeg'
],
maxCount
:
1
}
```
### 文件结构
```
pages/XingmaLabPublishPage/
├── XingmaLabPublishPage.vue # 主组件文件
├── XingmaLabPublishPage.less # 样式文件
├── config.js # 配置文件
├── README.md # 功能说明文档
└── CHANGELOG.md # 更新日志
```
### 兼容性
-
✅ 微信小程序
-
✅ uni-app框架
-
✅ Vue 3 Composition API
-
✅ 响应式设计
### 注意事项
1.
保持原有样式和图片格局完全不变
2.
所有交互遵循微信小程序开发规范
3.
错误处理完善,用户体验友好
4.
支持跨平台适配
5.
遵循项目开发规范
pages/XingmaLabPublishPage/README.md
0 → 100644
View file @
fc9295c6
# 星妈实验室发布页面
## 功能概述
这是一个星妈实验室的藏品发布页面,支持用户上传藏品图片、编辑文案介绍,并进行发布。
## 主要功能
### 1. 藏品图片上传
-
**限制数量**
:仅限上传1张图片
-
**尺寸限制**
:固定宽度,不限制高度比例
-
**大小限制**
:可配置最大文件大小(默认10MB)
-
**格式支持**
:jpg、png、jpeg
-
**交互方式**
:点击上传区域拉起相机/相册选择器
-
**错误提示**
:超过大小限制时显示"照片太大啦,换一张试试吧~"
### 2. 重新上传功能
-
**触发方式**
:点击"重新上传"按钮
-
**选择方式**
:拉起相机/相册图库
-
**格式限制**
:jpg/png/jpeg
-
**位置**
:已上传图片右下角
### 3. 藏品文案介绍
-
**字数限制**
:最多1000字
-
**输入方式**
:点击拉起输入键盘
-
**内容类型**
:纯文本,不支持富文本
-
**字数提示**
:实时显示当前字数/最大字数
-
**超限提示**
:达到上限时显示"字数已达上限"
### 4. 发布按钮交互
-
**首次发布**
:需要拉起微信头像昵称授权
-
**授权处理**
:
-
允许:进入确认弹窗页面
-
拒绝:停留当前页面,再次点击重新拉起授权
-
**非首次发布**
:直接进入确认弹窗页面
-
**确认弹窗**
:显示上传的图片和文案,用户确认后才发布
-
**次数限制**
:后端校验用户发布次数是否已达上限
## 技术实现
### 状态管理
-
`NOSEL`
:未选择状态
-
`SEL`
:选择状态(已上传图片和文案)
-
`SUC`
:发布成功状态
### 关键方法
-
`handleImageUpload()`
:处理图片上传
-
`handleDescriptionInput()`
:处理文案输入
-
`handlePublishBtnClick()`
:处理发布按钮点击
-
`requestUserInfo()`
:请求用户信息授权
-
`checkPublishLimit()`
:检查发布次数限制
### 配置项
-
图片大小限制:
`config.upload.maxSize`
-
文案字数限制:
`config.upload.maxWords`
-
支持的文件格式:
`config.upload.allowedTypes`
## 使用说明
1.
用户进入页面后,点击"记录这个时刻"按钮进入选择状态
2.
上传藏品图片(必填)
3.
输入藏品文案介绍(可选,最多1000字)
4.
点击发布按钮
5.
首次发布需要授权微信头像昵称
6.
确认发布内容后完成发布
7.
显示发布成功页面
## 注意事项
-
保持原有样式和图片格局不变
-
所有交互都遵循微信小程序规范
-
错误处理完善,用户体验友好
-
支持响应式布局
-
遵循Vue 3 Composition API开发规范
\ No newline at end of file
pages/XingmaLabPublishPage/XingmaLabPublishPage.less
0 → 100644
View file @
fc9295c6
// 星妈实验室发布页面样式
.xingmalabpublishpage {
width: 750rpx;
height: 1624rpx;
left: 0rpx;
top: 0rpx;
position: absolute;
.xingmalabpublishpagebg {
width: 750rpx;
height: 1624rpx;
left: 0rpx;
top: 0rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
// 返回按钮
.xingmalabpublishpagebackbtn {
width: 20rpx;
height: 33rpx;
left: 31rpx;
top: 88rpx;
position: absolute;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
z-index: 1000;
transition: opacity 0.3s ease;
&:hover {
opacity: 0.8;
}
}
// 未选择状态
.xingmalabpublishpagenosel {
width: 750rpx;
height: 1416rpx;
left: 0rpx;
top: 308rpx;
position: absolute;
.xingmalabpublishpagenoseltextplaceholder {
width: 684rpx;
height: 160rpx;
left: 33rpx;
top: 1129rpx;
position: absolute;
font-size: 32rpx;
line-height: 1.5;
color: rgba(0, 0, 0, 1);
border: none;
background: transparent;
resize: none;
outline: none;
&::placeholder {
color: rgba(189, 191, 195, 1);
}
}
.xingmalabpublishpagenoselbottomcon {
width: 750rpx;
height: 218rpx;
left: 0rpx;
top: 1378rpx;
position: absolute;
.xingmalabpublishpagenoselbottomconbg {
width: 750rpx;
height: 218rpx;
left: 0rpx;
top: 0rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.xingmalabpublishpagenoselbottomconbtn {
width: 686rpx;
height: 94rpx;
left: 32rpx;
top: 32rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
transition: opacity 0.3s ease;
&:hover {
opacity: 0.8;
}
}
}
.xingmalabpublishpagenoselbtn {
width: 686rpx;
height: 912rpx;
left: 32rpx;
top: 180rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
transition: opacity 0.3s ease;
&:hover {
opacity: 0.8;
}
}
}
// 主内容区域(整合未选择状态和选择状态)
.xingmalabpublishpagenosel {
// 选择状态下的文案输入框样式
&:has(.xingmalabpublishpageselbottomcon)
.xingmalabpublishpagenoseltextplaceholder {
width: 684rpx;
height: 160rpx;
left: 33rpx;
top: 1129rpx;
color: rgba(0, 0, 0, 1);
}
// 选择状态下的底部按钮区域
.xingmalabpublishpageselbottomcon {
width: 750rpx;
height: 218rpx;
left: 0rpx;
top: 1378rpx;
position: absolute;
.xingmalabpublishpageselbottomconpublishbtnbg {
width: 750rpx;
height: 218rpx;
left: 0rpx;
top: 0rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.xingmalabpublishpageselbottomconpublishbtn {
width: 686rpx;
height: 94rpx;
left: 32rpx;
top: 32rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
transition: opacity 0.3s ease;
&:hover {
opacity: 0.8;
}
// 禁用状态样式
&.disabled-publish-btn {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
&:hover {
opacity: 0.5;
}
}
}
}
// 已上传图片显示
.xingmalabpublishpageselpic {
width: 686rpx;
height: 912rpx;
left: 32rpx;
top: 180rpx;
position: absolute;
object-fit: contain;
border-radius: 16rpx;
background-color: #f8f9fa;
}
.xingmalabpublishpageselcpver {
width: 686rpx;
height: 189rpx;
left: 32rpx;
top: 903rpx;
position: absolute;
opacity: 0.3;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.xingmalabpublishpageselretry {
width: 270rpx;
height: 76rpx;
left: 240rpx;
top: 984rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
transition: opacity 0.3s ease;
&:hover {
opacity: 0.8;
}
}
}
// 成功状态
.xingmalabpublishpagesuc {
width: 750rpx;
height: 1416rpx;
left: 0rpx;
top: 308rpx;
position: absolute;
.xingmalabpublishpagesucbottomconicon {
width: 133rpx;
height: 152rpx;
left: 314rpx;
top: 182rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.xingmalabpublishpagesucbottomcon {
width: 750rpx;
height: 218rpx;
left: 0rpx;
top: 1375rpx;
position: absolute;
.xingmalabpublishpagesucbottomconbg {
width: 750rpx;
height: 218rpx;
left: 0rpx;
top: 0rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.xingmalabpublishpagesucbottomconbtn {
width: 686rpx;
height: 94rpx;
left: 32rpx;
top: 32rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
transition: opacity 0.3s ease;
&:hover {
opacity: 0.8;
}
}
}
.xingmalabpublishpagesucdesc {
width: 538rpx;
height: 117rpx;
left: 111rpx;
top: 371rpx;
position: absolute;
font-size: 30rpx;
color: rgba(29, 30, 37, 1);
line-height: 1.5;
text-align: left;
}
.xingmalabpublishpagesucpicbg {
width: 576rpx;
height: 812rpx;
left: 87rpx;
top: 521rpx;
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.xingmalabpublishpagesucpic {
width: 534rpx;
height: 708rpx;
left: 108rpx;
top: 536rpx;
position: absolute;
object-fit: contain;
border-radius: 16rpx;
background-color: #f8f9fa;
}
.xingmalabpublishpagesucnum {
width: 222rpx;
height: 25rpx;
left: 271rpx;
top: 1261rpx;
position: absolute;
font-size: 32rpx;
line-height: 25rpx;
color: rgba(178, 124, 30, 1);
text-align: center;
}
}
}
// 确认发布弹窗样式
.confirm-popup {
background: white;
border-radius: 24rpx;
padding: 40rpx;
width: 600rpx;
max-width: 90vw;
.confirm-title {
font-size: 36rpx;
font-weight: bold;
text-align: center;
margin-bottom: 40rpx;
color: #333;
}
.confirm-content {
margin-bottom: 40rpx;
.confirm-image {
width: 100%;
height: 300rpx;
margin-bottom: 20rpx;
border-radius: 16rpx;
overflow: hidden;
image {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.confirm-description {
font-size: 28rpx;
color: #666;
line-height: 1.5;
text-align: center;
padding: 20rpx;
background-color: #f8f9fa;
border-radius: 12rpx;
min-height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
.confirm-actions {
display: flex;
gap: 20rpx;
.confirm-btn {
flex: 1;
height: 80rpx;
border-radius: 40rpx;
font-size: 28rpx;
border: none;
transition: all 0.3s ease;
&.cancel {
background-color: #f0f0f0;
color: #666;
&:hover {
background-color: #e0e0e0;
}
}
&.confirm {
background-color: #007aff;
color: white;
&:hover {
background-color: #0056cc;
}
}
}
}
}
// 响应式适配
@media screen and (max-width: 750px) {
.xingmalabpublishpage {
width: 100vw;
height: 100vh;
.xingmalabpublishpagebg,
.xingmalabpublishpagenosel,
.xingmalabpublishpagesel,
.xingmalabpublishpagesuc {
width: 100%;
height: 100%;
left: 0;
top: 0;
}
.collection-image-area,
.collection-description-area {
position: relative;
left: auto;
top: auto;
margin: 20rpx auto;
width: 90%;
}
}
}
// 动画效果
.xingmalabpublishpage {
.xingmalabpublishpagenosel,
.xingmalabpublishpagesel,
.xingmalabpublishpagesuc {
animation: fadeIn 0.5s ease-in-out;
}
.collection-image-area,
.collection-description-area {
animation: slideInUp 0.8s ease-out 0.3s both;
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(50rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
// 上传状态样式
.upload-placeholder {
&.uploading {
opacity: 0.7;
pointer-events: none;
}
}
// 文案输入框焦点样式
.description-textarea {
&:focus {
box-shadow: 0 0 0 4rpx rgba(0, 122, 255, 0.2);
}
}
// 用户信息授权弹窗样式
.user-info-popup {
background: white;
border-radius: 24rpx 24rpx 0 0;
padding: 0;
width: 100%;
height: auto;
position: absolute;
bottom: -80rpx;
max-height: 80vh;
.user-info-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 40rpx 40rpx 20rpx;
border-bottom: 1rpx solid #ffffff;
.header-left {
display: flex;
align-items: center;
.xingma-logo {
width: 40rpx;
height: 40rpx;
margin-right: 16rpx;
border-radius: 60rpx;
border: none;
}
.app-name {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
}
}
.user-info-title {
font-size: 36rpx;
font-weight: bold;
text-align: left;
padding: 40rpx 40rpx 20rpx;
color: #333;
}
.user-info-content {
padding: 0 40rpx 40rpx;
.user-profile {
display: flex;
align-items: center;
padding: 30rpx 0;
border-bottom: 1rpx solid #f0f0f0;
margin-bottom: 30rpx;
.avatar-section {
margin-right: 30rpx;
.avatar-btn {
width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
border: none !important;
padding: 0;
background: transparent;
position: relative;
&::after {
border: none !important;
}
.avatar-image {
width: 100%;
height: 100%;
border-radius: 12rpx;
border: none;
object-fit: contain;
background-color: #f8f9fa;
}
.avatar-placeholder {
width: 100%;
height: 100%;
border-radius: 12rpx;
background-color: #ffffff;
display: flex;
align-items: center;
border: none;
justify-content: center;
.avatar-icon {
width: 100%;
height: 100%;
border-radius: 12rpx;
border: none;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
}
}
}
.nickname-section {
flex: 1;
.nickname-input {
width: 100%;
height: 60rpx;
border: none;
background: transparent;
font-size: 32rpx;
color: #333;
margin-bottom: 10rpx;
&::placeholder {
color: #999;
}
}
.nickname-label {
font-size: 24rpx;
color: #999;
}
}
.check-icon {
margin-left: 20rpx;
.check-mark {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
background-color: #07c160;
color: white;
font-size: 24rpx;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
}
}
}
.user-info-actions {
display: flex;
// padding: 0 40rpx 40rpx;
// gap: 20rpx;
margin-top: 0;
height: 180rpx;
justify-content: center;
.action-btn {
// flex: 1;
height: 88rpx;
width: 200rpx;
font-size: 32rpx;
border: none !important;
position: relative;
margin: 0 20rpx;
&::after {
border: none !important;
}
&.reject-btn {
background-color: #f0f0f0;
color: #666;
&:hover {
background-color: #f0f0f0;
}
}
&.allow-btn {
background-color: #07c160;
color: white;
&:hover:not(:disabled) {
background-color: #06ad56;
}
&:disabled {
background-color: #ccc;
color: #999;
}
}
}
}
}
// 调试信息样式
.debug-info {
position: absolute;
top: 20rpx;
right: 20rpx;
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 20rpx;
border-radius: 10rpx;
font-size: 24rpx;
z-index: 100;
max-width: 300rpx;
.debug-text {
display: block;
margin-bottom: 10rpx;
line-height: 1.4;
}
}
pages/XingmaLabPublishPage/XingmaLabPublishPage.vue
0 → 100644
View file @
fc9295c6
<
template
>
<view
class=
"xingmalabpublishpage "
>
<!--
<span
class=
"xingmalabpublishpagebg"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.background)})` }">
</span>
-->
<span
class=
"xingmalabpublishpagebackbtn"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.backBtn)})` }"
@click="handleGoBack">
</span>
<!-- 主内容区域 -->
<div
class=
"xingmalabpublishpagenosel"
v-if=
"currentState !== config.states.SUC"
>
<!-- 文案输入框 -->
<textarea
v-model=
"description"
class=
"xingmalabpublishpagenoseltextplaceholder"
:placeholder=
"hasContent ? config.texts.sel.descriptionPlaceholder : config.texts.noSel.placeholder"
:maxlength=
"config.upload.maxWords"
@
input=
"handleDescriptionInput"
></textarea>
<!-- 底部按钮区域 -->
<div
class=
"xingmalabpublishpagenoselbottomcon"
v-if=
"!hasContent"
>
<span
class=
"xingmalabpublishpagenoselbottomconbg"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.noSel.bottomConBg)})` }">
</span>
<span
class=
"xingmalabpublishpagenoselbottomconbtn"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.noSel.bottomConBtn)})` }">
</span>
</div>
<div
class=
"xingmalabpublishpageselbottomcon"
v-if=
"hasContent"
>
<span
class=
"xingmalabpublishpageselbottomconpublishbtnbg"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.sel.bottomConPublishBtnBg)})` }">
</span>
<span
class=
"xingmalabpublishpageselbottomconpublishbtn"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.sel.bottomConPublishBtn)})` }"
@click="handlePublishBtnClick">
</span>
</div>
<!-- 上传按钮 -->
<span
class=
"xingmalabpublishpagenoselbtn"
v-if=
"!hasContent"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.noSel.btn)})` }"
@click="handleImageUpload">
</span>
<!-- 已上传图片显示 -->
<image
v-if=
"uploadedImage"
:src=
"uploadedImage"
class=
"xingmalabpublishpageselpic"
mode=
"aspectFit"
/>
<span
class=
"xingmalabpublishpageselcpver"
v-if=
"uploadedImage"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.sel.cpver)})` }">
</span>
<span
class=
"xingmalabpublishpageselretry"
v-if=
"uploadedImage"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.sel.retry)})` }"
@click="handleImageUpload">
</span>
</div>
<!-- 成功状态 -->
<div
class=
"xingmalabpublishpagesuc"
v-if=
"currentState === config.states.SUC"
>
<span
class=
"xingmalabpublishpagesucbottomconicon"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.suc.bottomConIcon)})` }">
</span>
<div
class=
"xingmalabpublishpagesucbottomcon"
>
<span
class=
"xingmalabpublishpagesucbottomconbg"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.suc.bottomConBg)})` }">
</span>
<span
class=
"xingmalabpublishpagesucbottomconbtn"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.suc.bottomConBtn)})` }"
@click="handleSuccessBtnClick">
</span>
</div>
<span
class=
"xingmalabpublishpagesucdesc"
>
{{
successMessage
}}
</span>
<span
class=
"xingmalabpublishpagesucpicbg"
:style=
"
{ backgroundImage: `url(${$baseUrl}${getImageUrl(config.images.suc.picBg)})` }">
</span>
<image
v-if=
"uploadedImage"
:src=
"uploadedImage"
class=
"xingmalabpublishpagesucpic"
mode=
"aspectFit"
/>
<span
class=
"xingmalabpublishpagesucnum"
>
{{
config
.
texts
.
suc
.
numberPrefix
}}{{
publishNumber
}}
</span>
</div>
<!-- 确认发布弹窗 - 使用 Xingmalabconfirmpop 组件 -->
<Xingmalabconfirmpop
:visible=
"showConfirmPopup"
title=
"确认发布"
confirm-text=
"确认发布"
cancel-text=
"取消"
@
confirm=
"handleConfirmPublish"
@
cancel=
"handleCancelPublish"
@
close=
"showConfirmPopup = false"
/>
<!-- 无次数弹窗 - 使用 Xingmalabnotimepop 组件 -->
<Xingmalabnotimepop
:visible=
"showNoTimePopup"
title=
"发布次数已用完"
@
button-click=
"handleNoTimeButtonClick"
@
close=
"showNoTimePopup = false"
/>
<!-- 用户信息授权弹窗 -->
<uni-popup
ref=
"userInfoPopup"
type=
"bottom"
:mask-click=
"false"
>
<view
class=
"user-info-popup"
>
<view
class=
"user-info-header"
>
<view
class=
"header-left"
>
<image
:src=
"$baseUrl + getImageUrl(config.images.xingmaLogo)"
class=
"xingma-logo"
/>
<text
class=
"app-name"
>
星妈会
</text>
</view>
</view>
<view
class=
"user-info-title"
>
获取你的昵称、头像
</view>
<view
class=
"user-info-content"
>
<view
class=
"user-profile"
>
<view
class=
"avatar-section"
>
<button
class=
"avatar-btn"
open-type=
"chooseAvatar"
@
chooseavatar=
"onChooseAvatar"
>
<image
v-if=
"tempUserInfo.avatarUrl"
:src=
"tempUserInfo.avatarUrl"
class=
"avatar-image"
mode=
"aspectFit"
/>
<view
v-else
class=
"avatar-placeholder"
>
<image
:src=
"$baseUrl + getImageUrl(config.images.xingmaDefaultAvatar)"
class=
"avatar-icon"
/>
</view>
</button>
</view>
<view
class=
"nickname-section"
>
<input
type=
"nickname"
class=
"nickname-input"
:value=
"tempUserInfo.nickName"
@
input=
"onNicknameInput"
placeholder=
"请输入昵称"
/>
<view
class=
"nickname-label"
>
微信昵称头像
</view>
</view>
</view>
</view>
<view
class=
"user-info-actions"
>
<button
class=
"action-btn reject-btn"
@
click=
"handleRejectAuth"
>
拒绝
</button>
<button
class=
"action-btn allow-btn"
@
click=
"handleAllowAuth"
>
允许
</button>
</view>
</view>
</uni-popup>
</view>
</
template
>
<
script
setup
>
import
{
ref
,
onMounted
,
computed
}
from
'vue'
import
{
xingmaLabConfig
,
getImageUrl
,
getRandomSuccessMessage
}
from
'./config.js'
import
Xingmalabconfirmpop
from
'@/components/xingmaLab/Xingmalabconfirmpop.vue'
import
Xingmalabnotimepop
from
'@/components/xingmaLab/Xingmalabnotimepop.vue'
import
{
useXingmaLabStore
}
from
'@/stores/xingmaLab.js'
import
{
uploadImage
}
from
'@/api/common.js'
import
{
fetchRecordPublish
}
from
'@/api/xingmaLab.js'
import
md
from
'../../md'
;
// 组件名称
defineOptions
({
name
:
'XingmaLabPublishPage'
})
// 使用 store
const
xingmaLabStore
=
useXingmaLabStore
()
// 响应式数据
const
currentState
=
ref
(
xingmaLabConfig
.
states
.
NOSEL
)
// nosel, sel, suc
const
publishNumber
=
ref
(
''
)
const
uploadedImage
=
ref
(
''
)
// 上传的图片
const
description
=
ref
(
''
)
// 藏品文案介绍
const
isUploading
=
ref
(
false
)
// 上传状态
const
userInfoPopup
=
ref
(
null
)
// 用户信息授权弹窗引用
const
successMessage
=
ref
(
''
)
// 成功文案
const
tempUserInfo
=
ref
({
// 临时用户信息
avatarUrl
:
''
,
nickName
:
''
})
// 弹窗显示状态
const
showConfirmPopup
=
ref
(
false
)
// 确认发布弹窗
const
showNoTimePopup
=
ref
(
false
)
// 无次数弹窗
// 配置对象
const
config
=
xingmaLabConfig
// 计算属性 - 判断是否有内容(图片和文案都要有)
const
hasContent
=
computed
(()
=>
{
return
uploadedImage
.
value
&&
description
.
value
.
trim
()
})
// 计算属性 - 根据 store 中的信息判断
const
isFirstTimePublish
=
computed
(()
=>
{
// 通过头像昵称判断是否为首次发布
// 如果没有头像昵称信息,则为首次发布
return
!
hasUserInfo
.
value
})
const
hasUserInfo
=
computed
(()
=>
{
// 只检查 store 中的 xingmaInfo
const
{
xingmaInfo
}
=
xingmaLabStore
console
.
log
(
'🔍 hasUserInfo 检查:'
,
{
xingmaInfo
,
avatar
:
xingmaInfo
?.
avatar
,
nickname
:
xingmaInfo
?.
nickname
,
avatarType
:
typeof
xingmaInfo
?.
avatar
,
nicknameType
:
typeof
xingmaInfo
?.
nickname
})
if
(
xingmaInfo
&&
xingmaInfo
.
avatar
&&
xingmaInfo
.
nickname
)
{
console
.
log
(
'✅ Store 中有头像昵称信息'
)
return
true
}
return
false
})
const
canPublish
=
computed
(()
=>
{
// 根据 store 中的 remainingPublishCount 判断是否还有发布次数
const
{
xingmaInfo
}
=
xingmaLabStore
if
(
!
xingmaInfo
)
return
false
const
{
remainingPublishCount
,
isReachedLimit
}
=
xingmaInfo
return
remainingPublishCount
>
0
&&
!
isReachedLimit
})
const
publishCountInfo
=
computed
(()
=>
{
const
{
xingmaInfo
}
=
xingmaLabStore
if
(
!
xingmaInfo
)
{
return
{
current
:
0
,
max
:
0
,
remaining
:
0
}
}
const
{
currentMonthPublishCount
,
maxPublishCount
,
remainingPublishCount
}
=
xingmaInfo
return
{
current
:
currentMonthPublishCount
,
max
:
maxPublishCount
,
remaining
:
remainingPublishCount
}
})
// 图片上传处理
const
handleImageUpload
=
()
=>
{
if
(
uploadedImage
.
value
)
{
// 重新上传
//TODO:埋点
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"星妈lab-内容发布页"
,
componentName
:
"内容发布"
,
componentContent
:
"重新上传"
});
}
else
{
//TODO:埋点
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"星妈lab-内容发布页"
,
componentName
:
"内容发布"
,
componentContent
:
"点击添加图片"
});
}
if
(
isUploading
.
value
)
return
uni
.
chooseImage
({
count
:
1
,
sizeType
:
[
'original'
,
'compressed'
],
sourceType
:
[
'album'
,
'camera'
],
success
:
(
res
)
=>
{
////TODO:埋点--曝光
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab-内容发布页"
,
componentName
:
"内容发布"
,
componentContent
:
"重新上传"
});
const
tempFilePath
=
res
.
tempFilePaths
[
0
]
// 检查文件大小
uni
.
getFileInfo
({
filePath
:
tempFilePath
,
success
:
(
fileInfo
)
=>
{
if
(
fileInfo
.
size
>
config
.
upload
.
maxSize
)
{
uni
.
showToast
({
title
:
config
.
upload
.
maxSizeText
,
icon
:
'none'
,
duration
:
2000
})
return
}
// 检查文件格式
const
fileExtension
=
tempFilePath
.
split
(
'.'
).
pop
().
toLowerCase
()
if
(
!
config
.
upload
.
allowedTypes
.
includes
(
fileExtension
))
{
uni
.
showToast
({
title
:
'请选择jpg、png或jpeg格式的图片'
,
icon
:
'none'
,
duration
:
2000
})
return
}
// 保存临时文件路径,等待发布时上传
uploadedImage
.
value
=
tempFilePath
console
.
log
(
'🖼️ 图片已选择,等待发布时上传:'
,
tempFilePath
)
},
fail
:
()
=>
{
uni
.
showToast
({
title
:
'获取文件信息失败'
,
icon
:
'none'
})
}
})
},
fail
:
(
err
)
=>
{
console
.
log
(
'选择图片失败:'
,
err
)
}
})
}
// 上传图片到服务器
const
uploadImageFunc
=
async
(
tempFilePath
)
=>
{
isUploading
.
value
=
true
uni
.
showLoading
({
title
:
'上传中...'
,
mask
:
true
})
try
{
console
.
log
(
'📤 开始上传图片:'
,
tempFilePath
)
const
fs
=
uni
.
getFileSystemManager
();
const
base64
=
"data:image/jpeg;base64,"
+
fs
.
readFileSync
(
tempFilePath
,
"base64"
);
const
uploadRes
=
await
uploadImage
(
base64
);
if
(
uploadRes
.
success
)
{
// 保存接口返回的url,用于发布
const
uploadedUrl
=
uploadRes
.
data
?.
url
isUploading
.
value
=
false
uni
.
hideLoading
()
console
.
log
(
'✅ 图片上传成功,url:'
,
uploadedUrl
)
return
uploadedUrl
}
else
{
throw
new
Error
(
uploadRes
.
message
||
'图片上传失败'
)
}
}
catch
(
error
)
{
isUploading
.
value
=
false
uni
.
hideLoading
()
console
.
error
(
'❌ 图片上传失败:'
,
error
)
uni
.
showToast
({
title
:
error
.
message
||
'图片上传失败'
,
icon
:
"none"
,
});
throw
error
}
}
// 文案输入处理
const
handleDescriptionInput
=
(
e
)
=>
{
const
value
=
e
.
detail
.
value
if
(
value
.
length
>
config
.
upload
.
maxWords
)
{
uni
.
showToast
({
title
:
config
.
upload
.
maxWordsText
,
icon
:
'none'
,
duration
:
2000
})
description
.
value
=
value
.
substring
(
0
,
config
.
upload
.
maxWords
)
}
else
{
description
.
value
=
value
}
}
// 发布按钮点击处理
const
handlePublishBtnClick
=
async
()
=>
{
//TODO:埋点
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"星妈lab-内容发布页"
,
componentName
:
"内容发布"
,
componentContent
:
"发布"
});
console
.
log
(
'点击发布按钮'
,
{
isFirstTimePublish
:
isFirstTimePublish
.
value
,
hasUserInfo
:
hasUserInfo
.
value
,
canPublish
:
canPublish
.
value
,
publishCountInfo
:
publishCountInfo
.
value
})
// 检查是否首次发布且需要授权
if
(
isFirstTimePublish
.
value
&&
!
hasUserInfo
.
value
)
{
// 重置临时用户信息
tempUserInfo
.
value
=
{
avatarUrl
:
''
,
nickName
:
''
}
// 显示用户信息授权弹窗
userInfoPopup
.
value
.
open
()
return
}
// 检查发布次数限制
if
(
!
canPublish
.
value
)
{
// 显示无次数弹窗
showNoTimePopup
.
value
=
true
return
}
// 显示确认发布弹窗
showConfirmPopup
.
value
=
true
}
// 选择头像
const
onChooseAvatar
=
(
e
)
=>
{
console
.
log
(
'选择头像:'
,
e
.
detail
.
avatarUrl
)
tempUserInfo
.
value
.
avatarUrl
=
e
.
detail
.
avatarUrl
}
// 输入昵称
const
onNicknameInput
=
(
e
)
=>
{
console
.
log
(
'输入昵称:'
,
e
.
detail
.
value
)
tempUserInfo
.
value
.
nickName
=
e
.
detail
.
value
}
// 拒绝授权
const
handleRejectAuth
=
()
=>
{
userInfoPopup
.
value
.
close
()
uni
.
showToast
({
title
:
'需要授权才能发布'
,
icon
:
'none'
})
}
// 允许授权
const
handleAllowAuth
=
()
=>
{
console
.
log
(
'允许授权'
,
tempUserInfo
.
value
)
if
(
!
tempUserInfo
.
value
.
avatarUrl
)
{
uni
.
showToast
({
title
:
'请输入头像'
,
icon
:
'none'
})
return
}
if
(
!
tempUserInfo
.
value
.
nickName
)
{
uni
.
showToast
({
title
:
'请输入昵称'
,
icon
:
'none'
})
return
}
// 关闭授权弹窗
userInfoPopup
.
value
.
close
()
// 检查发布次数限制并显示确认弹窗
checkPublishLimitAndShowConfirm
()
}
// 检查发布次数限制并显示确认弹窗
const
checkPublishLimitAndShowConfirm
=
()
=>
{
// 直接使用计算属性判断
if
(
!
canPublish
.
value
)
{
// 显示无次数弹窗
showNoTimePopup
.
value
=
true
return
}
// 显示确认发布弹窗
showConfirmPopup
.
value
=
true
}
// 取消发布
const
handleCancelPublish
=
()
=>
{
showConfirmPopup
.
value
=
false
}
// 确认发布
const
handleConfirmPublish
=
async
()
=>
{
showConfirmPopup
.
value
=
false
try
{
console
.
log
(
'🚀 开始发布,当前状态:'
,
{
isFirstTimePublish
:
isFirstTimePublish
.
value
,
hasUserInfo
:
hasUserInfo
.
value
,
imgUrl
:
uploadedImage
.
value
,
content
:
description
.
value
})
// 执行发布
const
publishResult
=
await
performPublish
()
// 如果是首次授权发布成功,记录日志
if
(
isFirstTimePublish
.
value
)
{
console
.
log
(
'✅ 首次授权发布成功,用户信息:'
,
{
avatar
:
tempUserInfo
.
value
.
avatarUrl
,
nickname
:
tempUserInfo
.
value
.
nickName
})
}
// 发布成功后重新获取最新信息(如果需要的话)
// await xingmaLabStore.loadXingmaInfo()
// 切换到成功状态
currentState
.
value
=
config
.
states
.
SUC
successMessage
.
value
=
getRandomSuccessMessage
()
// 使用发布接口返回的 bizNo 作为发布编号
publishNumber
.
value
=
publishResult
.
data
?.
bizNo
//TODO:埋点--返回星妈会lab
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab-内容发布页"
,
componentName
:
"内容发布"
,
componentContent
:
"返回星妈会lab首页"
});
}
catch
(
error
)
{
console
.
error
(
'发布失败:'
,
error
)
uni
.
showToast
({
title
:
'发布失败,请重试'
,
icon
:
'none'
})
}
}
// 无次数弹窗按钮点击处理
const
handleNoTimeButtonClick
=
()
=>
{
showNoTimePopup
.
value
=
false
// 显示更详细的发布次数信息
// const { current, max, remaining } = publishCountInfo.value
// uni.showToast({
// title: `本月已发布${current}次,剩余${remaining}次`,
// icon: 'none',
// duration: 3000
// })
}
// 移除不再需要的 checkPublishLimit 函数
// const checkPublishLimit = async () => {
// // 这里应该调用后端接口检查发布次数
// // 暂时返回true作为示例,实际使用时应该根据后端返回结果判断
// return new Promise((resolve) => {
// setTimeout(() => {
// // 模拟检查结果,这里可以改为实际的接口调用
// const hasRemainingCount = Math.random() > 0.3 // 70% 概率有剩余次数
// resolve(hasRemainingCount)
// }, 500)
// })
// }
// 返回上一页
const
handleGoBack
=
()
=>
{
// 检查是否有上一页
const
pages
=
getCurrentPages
()
console
.
log
(
'pages'
,
pages
)
if
(
pages
.
length
>
1
)
{
// 有上一页,直接返回上一页(收藏状态已在更新时同步)
uni
.
navigateBack
({
delta
:
1
})
}
else
{
// 没有上一页,跳转到星妈实验室页面,并传递index参数
uni
.
redirectTo
({
url
:
`/pages/xingmaLab/xingmaLab`
})
}
}
// 执行发布
const
performPublish
=
async
()
=>
{
try
{
// 调用实际的发布接口
const
params
=
{
imgUrl
:
uploadedImage
.
value
,
// 初始时是临时文件路径,将在下面上传
content
:
description
.
value
}
// 上传内容图片
if
(
uploadedImage
.
value
)
{
try
{
const
uploadedUrl
=
await
uploadImageFunc
(
uploadedImage
.
value
)
params
.
imageUrl
=
uploadedUrl
console
.
log
(
'✅ 内容图片上传成功,更新 imgUrl:'
,
uploadedUrl
)
}
catch
(
uploadError
)
{
console
.
error
(
'❌ 内容图片上传失败:'
,
uploadError
)
throw
new
Error
(
'内容图片上传失败,请重试'
)
}
}
// 如果是首次授权,需要传递nickname和avatar
if
(
isFirstTimePublish
.
value
)
{
// 直接从临时用户信息中读取,不存储到本地
console
.
log
(
'🔍 检查临时用户信息:'
,
tempUserInfo
.
value
);
if
(
tempUserInfo
.
value
&&
tempUserInfo
.
value
.
avatarUrl
&&
tempUserInfo
.
value
.
nickName
)
{
params
.
nickname
=
tempUserInfo
.
value
.
nickName
// 上传头像到服务器,使用返回的URL
try
{
console
.
log
(
'🖼️ 开始上传头像:'
,
tempUserInfo
.
value
.
avatarUrl
)
// 将临时文件路径转换为base64
const
fs
=
uni
.
getFileSystemManager
()
const
avatarBase64
=
"data:image/jpeg;base64,"
+
fs
.
readFileSync
(
tempUserInfo
.
value
.
avatarUrl
,
"base64"
)
const
avatarUploadRes
=
await
uploadImage
(
avatarBase64
)
if
(
avatarUploadRes
.
success
)
{
params
.
avatar
=
avatarUploadRes
.
data
?.
url
console
.
log
(
'✅ 头像上传成功,avatar URL:'
,
params
.
avatar
)
}
else
{
throw
new
Error
(
avatarUploadRes
.
message
||
'头像上传失败'
)
}
}
catch
(
avatarError
)
{
console
.
error
(
'❌ 头像上传失败:'
,
avatarError
)
throw
new
Error
(
'头像上传失败,请重试'
)
}
}
else
{
console
.
warn
(
'⚠️ 临时用户信息不完整,无法上传头像:'
,
tempUserInfo
.
value
);
}
}
console
.
log
(
'🚀 发布参数:'
,
params
)
// 使用 fetchRecordPublish 调用发布接口
const
result
=
await
fetchRecordPublish
(
params
)
console
.
log
(
'📤 发布接口返回:'
,
result
)
if
(
result
.
success
)
{
console
.
log
(
'✅ 发布成功'
)
return
result
}
else
{
throw
new
Error
(
result
.
message
||
'发布失败'
)
}
}
catch
(
error
)
{
console
.
error
(
'❌ 发布失败:'
,
error
)
throw
error
}
}
// 生成发布编号
const
generatePublishNumber
=
()
=>
{
return
Math
.
random
().
toString
().
slice
(
2
,
11
)
}
const
handleSuccessBtnClick
=
()
=>
{
console
.
log
(
'点击成功状态按钮'
)
//TODO:埋点
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"星妈lab-内容发布页"
,
componentName
:
"内容发布"
,
componentContent
:
"返回星妈会lab首页"
});
// 这里可以添加完成后的跳转逻辑
// uni.navigateBack()
uni
.
redirectTo
({
url
:
'/pages/xingmaLab/xingmaLab'
})
}
// 生命周期
onMounted
(
async
()
=>
{
console
.
log
(
'星妈实验室发布页面已加载'
)
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab-内容发布页"
,
componentName
:
"内容发布"
,
componentContent
:
"点击添加图片"
});
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab-内容发布页"
,
componentName
:
"内容发布"
,
componentContent
:
"发布"
});
// 获取最新的星妈实验室信息
await
xingmaLabStore
.
loadXingmaInfo
()
// 调试信息:查看加载后的数据状态
console
.
log
(
'🚀 页面加载完成后的状态:'
,
{
xingmaInfo
:
xingmaLabStore
.
xingmaInfo
,
hasUserInfo
:
hasUserInfo
.
value
,
isFirstTimePublish
:
isFirstTimePublish
.
value
,
canPublish
:
canPublish
.
value
,
publishCountInfo
:
publishCountInfo
.
value
})
// 生成随机成功文案
successMessage
.
value
=
getRandomSuccessMessage
()
// 重置临时用户信息
// tempUserInfo.value = {
// avatarUrl: '',
// nickName: ''
// }
// // 显示用户信息授权弹窗
// userInfoPopup.value.open()
})
</
script
>
<
style
lang=
"less"
scoped
>
@import './XingmaLabPublishPage.less';
</
style
>
pages/XingmaLabPublishPage/config.js
0 → 100644
View file @
fc9295c6
const
version
=
'v1'
// 星妈实验室发布页面配置
export
const
xingmaLabConfig
=
{
// 图片资源路径配置
images
:
{
// 背景图片
background
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabPublishPageBg.png`
,
// 返回按钮
backBtn
:
`XingmaLabDetailPage/
${
version
}
/XingmaLabDetailPageBackBtn.png`
,
xingmaLogo
:
`XingmaLabPublishPage/
${
version
}
/XingmaLogo.png`
,
xingmaDefaultAvatar
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabDefaultAvatar.png`
,
// 未选择状态图片
noSel
:
{
bottomConBg
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabPublishPageNoSelBottomConBg.png`
,
bottomConBtn
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabPublishPageNoSelBottomConBtn.png`
,
btn
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabPublishPageNoSelBtn.png`
},
// 选择状态图片
sel
:
{
bottomConPublishBtnBg
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabPublishPageSelBottomConPublishBtnBg.png`
,
bottomConPublishBtn
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabPublishPageSelBottomConPublishBtn.png`
,
pic
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabPublishPageSelPic.png`
,
cpver
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabPublishPageSelCpver.png`
,
retry
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabPublishPageSelRetry.png`
},
// 成功状态图片
suc
:
{
bottomConIcon
:
`XingmaLabPublishPage/
${
version
}
/suc_icon3.png`
,
bottomConBg
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabPublishPageSucBottomConBg.png`
,
bottomConBtn
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabPublishPageSucBottomConBtn.png`
,
picBg
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabPublishPageSucPicBg.png`
,
pic
:
`XingmaLabPublishPage/
${
version
}
/XingmaLabPublishPageSucPic.png`
},
// 返回按钮
backBtn
:
`XingmaLabDetailPage/
${
version
}
/XingmaLabDetailPageBackBtn.png`
},
// 页面状态配置
states
:
{
NOSEL
:
'nosel'
,
// 未选择状态
SEL
:
'sel'
,
// 选择状态
SUC
:
'suc'
// 成功状态
},
// 文案配置
texts
:
{
noSel
:
{
placeholder
:
'记录这个时刻……'
},
sel
:
{
title
:
'快来用星妈会小程序'
,
descriptionPlaceholder
:
'请输入藏品文案介绍...'
},
suc
:
{
numberPrefix
:
'No.'
,
desc
:
'发布成功!'
}
},
// 发布成功文案配置
successMessages
:
[
'最好的礼物不是玩具,是陪宝贝长大的光阴。欢迎将宝贝的珍贵回忆,存入你的"时光银行"。'
,
'时光会走远,影像能长存。星妈会,为您珍藏每一份稚的美好。'
,
'孩子终将长大,但「星妈会Lab」会帮你永远记得宝贝现在的样子。'
,
'孩子是我们写在时光里的诗,每一次记录,都是爱的注脚。'
,
'照片是时间的化石,为易逝的童年建立不朽的纪念碑。'
,
'有一天,孩子会离开我去闯荡世界。所以现在,我们要认真记录现在ta依恋我们的样子。'
,
'父母与子女的缘分,就是不断目送他的背影渐行渐远。而照片,能让那背影在记忆中永不模糊。'
],
// 图片上传配置
upload
:
{
maxSize
:
10
*
1024
*
1024
,
// 10MB,待定
maxSizeText
:
'照片太大啦,换一张试试吧~'
,
maxWords
:
1000
,
maxWordsText
:
'字数已达上限'
,
allowedTypes
:
[
'jpg'
,
'png'
,
'jpeg'
],
maxCount
:
1
}
}
// 获取完整图片URL
export
const
getImageUrl
=
(
imagePath
)
=>
{
return
`
${
imagePath
}
`
}
// 获取状态对应的图片配置
export
const
getStateImages
=
(
state
)
=>
{
switch
(
state
)
{
case
xingmaLabConfig
.
states
.
NOSEL
:
return
xingmaLabConfig
.
images
.
noSel
case
xingmaLabConfig
.
states
.
SEL
:
return
xingmaLabConfig
.
images
.
sel
case
xingmaLabConfig
.
states
.
SUC
:
return
xingmaLabConfig
.
images
.
suc
default
:
return
xingmaLabConfig
.
images
.
noSel
}
}
// 获取随机成功文案
export
const
getRandomSuccessMessage
=
()
=>
{
const
messages
=
xingmaLabConfig
.
successMessages
const
randomIndex
=
Math
.
floor
(
Math
.
random
()
*
messages
.
length
)
return
messages
[
randomIndex
]
}
pages/XingmaLabPublishPage/test-popup.vue
0 → 100644
View file @
fc9295c6
<
template
>
<view
class=
"test-page"
>
<view
class=
"header"
>
<text
class=
"title"
>
弹窗组件测试页面
</text>
</view>
<view
class=
"content"
>
<view
class=
"button-group"
>
<button
class=
"btn btn-primary"
@
click=
"showConfirmPopup = true"
>
显示确认弹窗
</button>
<button
class=
"btn btn-warning"
@
click=
"showNoTimePopup = true"
>
显示无次数弹窗
</button>
</view>
</view>
<!-- 确认弹窗 -->
<Xingmalabconfirmpop
:visible=
"showConfirmPopup"
title=
"确认发布"
confirm-text=
"确认发布"
cancel-text=
"取消"
@
confirm=
"handleConfirm"
@
cancel=
"handleCancel"
@
close=
"showConfirmPopup = false"
/>
<!-- 无次数弹窗 -->
<Xingmalabnotimepop
:visible=
"showNoTimePopup"
title=
"发布次数已用完"
@
button-click=
"handleNoTimeButtonClick"
@
close=
"showNoTimePopup = false"
/>
</view>
</
template
>
<
script
setup
>
import
{
ref
}
from
'vue'
import
Xingmalabconfirmpop
from
'@/components/xingmaLab/Xingmalabconfirmpop.vue'
import
Xingmalabnotimepop
from
'@/components/xingmaLab/Xingmalabnotimepop.vue'
// 弹窗显示状态
const
showConfirmPopup
=
ref
(
false
)
const
showNoTimePopup
=
ref
(
false
)
// 确认弹窗事件处理
const
handleConfirm
=
()
=>
{
uni
.
showToast
({
title
:
'确认发布'
,
icon
:
'success'
})
showConfirmPopup
.
value
=
false
}
const
handleCancel
=
()
=>
{
uni
.
showToast
({
title
:
'取消发布'
,
icon
:
'none'
})
showConfirmPopup
.
value
=
false
}
// 无次数弹窗事件处理
const
handleNoTimeButtonClick
=
()
=>
{
uni
.
showToast
({
title
:
'发布次数已用完'
,
icon
:
'none'
})
showNoTimePopup
.
value
=
false
}
</
script
>
<
style
lang=
"less"
scoped
>
.test-page {
padding: 40rpx;
background-color: #f5f5f5;
min-height: 100vh;
}
.header {
text-align: center;
margin-bottom: 60rpx;
.title {
font-size: 48rpx;
font-weight: bold;
color: #333;
}
}
.content {
.debug-info {
margin-bottom: 30rpx;
padding: 20rpx;
background-color: #e0e0e0;
border-radius: 10rpx;
font-size: 28rpx;
color: #555;
.debug-title {
font-weight: bold;
margin-bottom: 10rpx;
}
.debug-item {
margin-bottom: 5rpx;
}
}
.button-group {
display: flex;
flex-direction: column;
gap: 30rpx;
.btn {
padding: 30rpx;
border-radius: 16rpx;
border: none;
font-size: 32rpx;
font-weight: 500;
&.btn-primary {
background-color: #007aff;
color: white;
}
&.btn-warning {
background-color: #ff3b30;
color: white;
}
&:active {
opacity: 0.8;
}
}
}
}
</
style
>
pages/xingmaLab/xingmaLab.less
0 → 100644
View file @
fc9295c6
// 星妈Lab页面样式
.xingma-lab-container {
// min-height: 100vh;
background-color: #fff;
position: relative;
padding-bottom: 200rpx; // 为底部导航留出空间
overflow: visible;
// height: 100vh;
// 第一层:顶部导航
.top-navigation {
display: flex;
// align-items: center;
// justify-content: space-between;
height: 165rpx;
background-color: #ffffff;
position: sticky;
z-index: 100;
top: 0;
overflow: visible;
.nav-left {
width: 90rpx;
// height: 60rpx;
.back-btn {
width: 60rpx;
height: 60rpx;
margin-top: 88rpx;
margin-left: 30rpx;
}
}
.nav-center {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
.nav-title {
font-size: 36rpx;
font-weight: bold;
margin-top: 68rpx;
color: #333333;
}
}
.nav-right {
width: 90rpx;
}
}
// 第二层:内容区域
.content-area {
height: 80vh;
overflow: visible;
// flex: 1;
// 藏馆内容 - 单列瀑布流
.cangguan-content {
position: relative;
height: 81.2vh;
// overflow: auto;
// height:1624rpx;
.banner_content{
margin-top: 20rpx;
margin-left: 22.5rpx;
width: 705rpx;
height: 151rpx;
margin-bottom: 20rpx;
.banner_img{
border-radius: 16rpx;
width: 100%;
height: 100%;
}
}
.item_cangguan{
margin-left: 22rpx;
width: 707rpx;
height:auto;
.item_cangguan_img1{
width: 100%;
height: auto;
position: relative;
.item_cangguan_img{
width: 100%;
height: auto;
}
.item_cangguan_img_up{
position: absolute;
left: 50%;
top: 15rpx;
transform: translateX(-50%);
width: 100%;
height: 100%;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.2);
}
}
.item_cangguan_bottom{
position: absolute;
margin-top: -104rpx;
width: 707rpx;
height: 96rpx;
.item_cangguan_bottom_bg{
position: absolute;
width: 100%;
height: 96rpx;
background-color: rgba(178, 124, 30, 0.45);
backdrop-filter: blur(10rpx);
-webkit-backdrop-filter: blur(10rpx);
}
.item_logo{
position: absolute;
margin-top: 20rpx;
width: 202rpx;
height: 52rpx;
left: 124rpx;
}
.title_line{
position: absolute;
margin-top: 32rpx;
width: 1rpx;
height: 34rpx;
background-color: #ffffff;
left: 50%;
transform: translateX(-50%);
}
.nick_name_content{
position: absolute;
left: 385rpx;
right: 10rpx;
margin-top: 20rpx;
.nick_name{
position: absolute;
font-size: 22rpx;
font-weight: bold;
color: #ffffff;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width:260rpx;
}
.user_num{
margin-top: 30rpx;
position: absolute;
font-size: 18rpx;
color: #ffffff;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width:260rpx;
}
}
}
.item_cangguan_text{
width: 707rpx;
margin-top: 25rpx;
margin-bottom: 40rpx;
.item_desc{
font-size: 36rpx;
color: #000;
font-weight: 400;
width: 707rpx;
height: 50rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
max-width: 707rpx;
word-break: keep-all;
}
.nicheng_shoucang_zhaungtai{
position: relative;
width: 100%;
height: 48rpx;
margin-top: 16rpx;
.nicheng_shoucang_item{
position: relative;
width: 100%;
height: 100%;
.avatar_img{
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 48rpx;
height: 48rpx;
border-radius: 50%;
object-fit: contain;
background-color: #f8f9fa;
}
.nick_name_text{
position: absolute;
left: 50rpx;
top: 50%;
transform: translateY(-50%);
font-size: 24rpx;
color: #6f6d67;
margin-left: 13rpx;
}
.shoucang_icon{
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 32rpx;
height: 32rpx;
}
.shoucang_text{
position: absolute;
right: 40rpx;
top: 50%;
transform: translateY(-50%);
font-size: 24rpx;
color: #6f6d67;
}
}
}
}
}
}
// 我的藏馆内容
.wodecangguan-content {
overflow: visible;
height: 77.8vh;
width: 100%;
.sub-tab-container {
display: flex;
background-color: #ffffff;
margin-bottom: 20rpx;
height: 80rpx;
overflow: hidden;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.sub-tab-item {
flex: 1;
// padding: 24rpx 0;
text-align: center;
position: relative;
// transition: all 0.3s ease;
display: flex;
flex-direction: column;
align-items: center;
// justify-content: center;
&.active {
.sub-tab-text {
color: #1d1e25;
font-weight: bold;
margin-top: 20rpx;
}
.sub-tab-line{
width: 32rpx;
height: 6rpx;
background-color: #d3a358;
border-radius: 3rpx;
margin-top: 16rpx;
}
}
.sub-tab-text {
margin-top: 20rpx;
font-size: 28rpx;
color: #a8a8a9;
// transition: all 0.3s ease;
}
.sub-tab-line{
width: 32rpx;
height: 6rpx;
background-color: #fff;
border-radius: 3rpx;
}
}
}
.wodecangpin-content {
// padding-left:12rpx;
height: 72vh;
width: 100%;
overflow: visible;
.waterfall-list-noval {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 72vh;
width: 100%;
.noval-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.noval-illustration {
width: 280rpx;
height: 240rpx;
// margin-bottom: 40rpx;
display: flex;
align-items: center;
justify-content: center;
.noval-img {
width: 280rpx;
height: 240rpx;
}
}
.noval-tip {
font-size: 28rpx;
color: #1d1e25;
text-align: center;
margin-bottom: 50rpx;
line-height: 1.4;
}
.publish-btn {
background-color: #d3a358;
border-radius: 49rpx;
// padding: 20rpx 40rpx;
box-shadow: 0 4rpx 12rpx rgba(211, 163, 88, 0.3);
width: 323rpx;
height: 98rpx;
display: flex;
align-items: center;
justify-content: center;
.publish-text {
color: #ffffff;
font-size: 28rpx;
// font-weight: bold;
}
}
}
}
.waterfall-list1 {
position: absolute;
// display: grid;
// flex-wrap: wrap;
// grid-template-columns: 1fr 1fr;
// gap: 12rpx;
// height: 1624rpx;
// padding: 0 12rpx;
height: 72vh;
width:100%;
.waterfall-item {
background-color: #ffffff;
// border-radius: 16rpx;
overflow: hidden;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
position: relative;
width: 360rpx;
height: auto;
transition: transform 0.3s ease, box-shadow 0.3s ease;
// &:active {
// transform: scale(0.98);
// box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.15);
// }
.item-up-content{
position: relative;
width: 100%;
height: auto;
.item-image {
width: 100%;
height: auto;
background-color: #f0f0f0;
border-radius: 16rpx 16rpx 0rpx 0rpx;
}
.item-num {
position: absolute;
background-color: #fde0a5;
width: 212rpx;
height: 44rpx;
border-radius: 0rpx 12rpx 0rpx 0rpx;
bottom: 8rpx;
left: 0;
.badge-num {
position: absolute;
color: #b27c1e;
font-size: 24rpx;
width: 100%;
text-align: center;
top: 50%;
transform: translateY(-50%);
line-height: 1;
}
}
.item-badge {
position: absolute;
background-color: #d3a358;
width: 114rpx;
height: 48rpx;
border-radius: 12rpx 0rpx;
top: 0;
left: 0;
.badge-text {
position: absolute;
color: #ffffff;
font-size: 24rpx;
left: 10rpx;
top: 8rpx;
}
}
}
.item-info {
padding: 16rpx;
.item-title {
font-size: 28rpx;
// font-weight: bold;
color: #1d1e25;
// line-height: 1.4;
width: 320rpx;
height: 40rpx;
margin-bottom: 12rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
max-width: 320rpx;
word-break: keep-all;
}
.item-meta {
display: flex;
justify-content: space-between;
align-items: center;
.creator-info {
display: flex;
align-items: center;
gap: 6rpx;
.creator-avatar{
width: 40rpx;
height: 40rpx;
border-radius: 50%;
object-fit: contain;
background-color: #f8f9fa;
}
.creator-name {
font-size: 24rpx;
color: #6f6d67;
}
}
}
}
}
}
}
.sub-tab-content{
// padding-left:12rpx;
height: 72vh;
width: 100%;
overflow: visible;
.waterfall-list-noval2 {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 72vh;
width: 100%;
.noval-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.noval-illustration {
width: 280rpx;
height: 240rpx;
// margin-bottom: 40rpx;
display: flex;
align-items: center;
justify-content: center;
.noval-img {
width: 280rpx;
height: 240rpx;
}
}
.noval-tip {
font-size: 28rpx;
color: #1d1e25;
text-align: center;
margin-bottom: 50rpx;
line-height: 1.4;
}
}
}
.waterfall-list1 {
position: absolute;
// display: grid;
// flex-wrap: wrap;
// grid-template-columns: 1fr 1fr;
// gap: 12rpx;
// height: 1624rpx;
// padding: 0 12rpx;
height: 72vh;
width:100%;
.waterfall-item {
background-color: #ffffff;
// border-radius: 16rpx;
overflow: hidden;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
position: relative;
width: 360rpx;
height: auto;
transition: transform 0.3s ease, box-shadow 0.3s ease;
// &:active {
// transform: scale(0.98);
// box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.15);
// }
.item-up-content{
position: relative;
width: 100%;
height: auto;
.item-image {
width: 100%;
height: auto;
background-color: #f0f0f0;
border-radius: 16rpx 16rpx 0rpx 0rpx;
}
.item-num {
position: absolute;
background-color: #fde0a5;
width: 212rpx;
height: 44rpx;
border-radius: 0rpx 12rpx 0rpx 0rpx;
bottom: 8rpx;
left: 0;
.badge-num {
position: absolute;
color: #b27c1e;
font-size: 24rpx;
width: 100%;
text-align: center;
top: 50%;
transform: translateY(-50%);
line-height: 1;
}
}
.item-badge {
position: absolute;
background-color: #d3a358;
width: 114rpx;
height: 48rpx;
border-radius: 12rpx 0rpx;
top: 0;
left: 0;
.badge-text {
position: absolute;
color: #ffffff;
font-size: 24rpx;
left: 10rpx;
top: 8rpx;
}
}
}
.item-info {
padding: 16rpx;
.item-title {
font-size: 28rpx;
// font-weight: bold;
color: #1d1e25;
// line-height: 1.4;
width: 320rpx;
height: 40rpx;
margin-bottom: 12rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
max-width: 320rpx;
word-break: keep-all;
}
.item-meta {
display: flex;
justify-content: space-between;
align-items: center;
.creator-info {
display: flex;
align-items: center;
gap: 6rpx;
.creator-avatar{
width: 40rpx;
height: 40rpx;
border-radius: 50%;
object-fit: contain;
background-color: #f8f9fa;
}
.creator-name {
font-size: 24rpx;
color: #6f6d67;
}
}
}
}
}
}
}
}
}
// 底部导航
.bottom-navigation {
position: fixed;
bottom: 0;
width: 750rpx;
height: 180rpx;
background-color: #ffffff;
display: flex;
align-items: center;
justify-content: space-around;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
z-index: 100;
.bottom-nav-item {
display: flex;
flex-direction: column;
align-items: center;
// cursor: pointer;
// transition: all 0.3s ease;
// &:active {
// transform: scale(0.95);
// }
.bottom-nav-icon {
width: 100rpx;
height: 90rpx;
}
}
// 第一个导航项的特殊样式
.bottom-nav-item1 {
display: flex;
flex-direction: column;
align-items: center;
// cursor: pointer;
// transition: all 0.3s ease;
// &:active {
// transform: scale(0.95);
// }
.bottom-nav-icon1 {
width: 100rpx;
height: 90rpx;
}
}
// 第二个导航项的特殊样式(发布按钮)
.bottom-nav-item2 {
margin-top: -100rpx;
// display: flex;
// flex-direction: column;
// align-items: center;
// cursor: pointer;
// transition: all 0.3s ease;
// &:active {
// transform: scale(0.95);
// }
.publish-icon {
width: 130rpx;
height: 152rpx;
}
}
// 第三个导航项的特殊样式
.bottom-nav-item3 {
display: flex;
flex-direction: column;
align-items: center;
// cursor: pointer;
// transition: all 0.3s ease;
// &:active {
// transform: scale(0.95);
// }
.bottom-nav-icon3 {
width: 100rpx;
height: 90rpx;
}
}
}
}
.grid-view {
transition: none !important;
animation: none !important;
}
\ No newline at end of file
pages/xingmaLab/xingmaLab.vue
0 → 100644
View file @
fc9295c6
<
template
>
<view
class=
"xingma-lab-container"
>
<!-- 第一层:顶部导航 -->
<view
class=
"top-navigation"
>
<view
class=
"nav-left"
>
<image
class=
"back-btn"
:src=
"$baseUrl + `xingmaLab/1001/backBtn.png`"
mode=
"aspectFit"
@
click=
"handleBack"
/>
</view>
<view
class=
"nav-center"
>
<text
class=
"nav-title"
>
星妈会Lab
</text>
</view>
<view
class=
"nav-right"
></view>
</view>
<!-- 第二层:内容区域 -->
<view
class=
"content-area"
>
<!-- 藏馆内容 - 单列瀑布流 -->
<scroll-view
v-if=
"activeTab === 'cangguan'"
scroll-y=
"true"
class=
"cangguan-content"
@
scrolltolower=
"handleScroll_cangguan"
>
<view
class=
"banner_content"
>
<image
class=
"banner_img"
:src=
"$baseUrl + `xingmaLab/1001/bannerImg0.png`"
mode=
"aspectFill"
/>
</view>
<view
v-for=
"(item, index) in cangguanList"
:key=
"index"
class=
"item_cangguan"
@
click=
"handleItemClick_cangguan(item, index)"
>
<!--
<image
class=
"item_cangguan_img"
:src=
"`$
{item.imgUrl}`" mode="widthFix">
<image
class=
"item_cangguan_img_up"
:src=
"`$
{item.imgUrl}`" mode="widthFix">
</image>
</image>
-->
<view
class=
"item_cangguan_img1"
:style=
"`background-image: url($
{item.imgUrl}); background-size: 707rpx auto; background-repeat: no-repeat;`"
mode="widthFix">
<image
class=
"item_cangguan_img"
:src=
"`$
{item.imgUrl}`" mode="widthFix" @load="(e) => handleImageLoad(e, item, index)">
</image>
<image
class=
"item_cangguan_img_up"
:src=
"`$
{item.imgUrl}`" mode="aspectFill" :style="`width: ${item.targetWidth - 30}rpx; height: ${item.targetHeight - 120}rpx;`">
</image>
</view>
<view
class=
"item_cangguan_bottom"
>
<view
class=
"item_cangguan_bottom_bg"
>
</view>
<image
class=
"item_logo"
:src=
"$baseUrl + `xingmaLab/1001/item_logo_cangguan.png`"
mode=
"aspectFill"
/>
<view
class=
"title_line"
></view>
<view
class=
"nick_name_content"
>
<text
class=
"nick_name"
>
No.
{{
item
.
bizNo
}}
</text>
<text
class=
"user_num"
>
By.
{{
item
.
nickname
}}
</text>
</view>
</view>
<view
class=
"item_cangguan_text"
>
<text
class=
"item_desc"
>
{{
item
.
content
}}
</text>
<view
class=
"nicheng_shoucang_zhaungtai"
>
<view
class=
"nicheng_shoucang_item"
>
<image
class=
"avatar_img"
:src=
"`$
{item.avatar}`" mode="aspectFit" />
<text
class=
"nick_name_text"
>
{{
item
.
nickname
}}
</text>
<text
class=
"shoucang_text"
>
{{
item
.
collection
?
'已收藏'
:
'未收藏'
}}
</text>
<image
class=
"shoucang_icon"
:src=
"item.collection ? $baseUrl + `xingmaLab/1001/shoucang_on.png` : $baseUrl + `xingmaLab/1001/shoucang_off.png`"
mode=
"aspectFit"
/>
</view>
</view>
</view>
</view>
</scroll-view>
<!-- 我的藏馆内容 - 双切页两列瀑布流 -->
<view
v-if=
"activeTab === 'wodecangguan'"
class=
"wodecangguan-content"
>
<!-- 切页tab -->
<view
class=
"sub-tab-container"
>
<view
class=
"sub-tab-item"
:class=
"
{ active: activeSubTab === 'collections' }"
@click="switchSubTab('collections')">
<text
class=
"sub-tab-text"
>
我的藏品
</text>
<view
class=
"sub-tab-line"
></view>
</view>
<view
class=
"sub-tab-item"
:class=
"
{ active: activeSubTab === 'favorites' }"
@click="switchSubTab('favorites')">
<text
class=
"sub-tab-text"
>
我的收藏
</text>
<view
class=
"sub-tab-line"
></view>
</view>
</view>
<!-- 我的藏品列表 - 使用与藏馆相同的数据 -->
<view
v-if=
"activeSubTab === 'collections'"
class=
"wodecangpin-content"
>
<view
class=
"waterfall-list-noval"
v-if=
"!(cangpinList && cangpinList.length > 0)"
>
<view
class=
"noval-content"
>
<!-- 卡片插图 -->
<view
class=
"noval-illustration"
>
<image
class=
"noval-img"
:src=
"$baseUrl + `xingmaLab/1001/cangpin_noval_img0.png`"
mode=
"aspectFit"
/>
</view>
<!-- 提示文字 -->
<text
class=
"noval-tip"
>
快去发布属于你的藏品吧!
</text>
<!-- 发布按钮 -->
<view
class=
"publish-btn"
@
click=
"handlePublish"
>
<text
class=
"publish-text"
>
去发布
</text>
</view>
</view>
</view>
<scroll-view
class=
"waterfall-list1"
scroll-y=
"true"
@
scrolltolower=
"handleScrollToLower_cangpin"
v-if=
"cangpinList && cangpinList.length > 0"
>
<grid-view
column=
"2"
main-axis-gap=
"
{{
10
}}
" cross-axis-gap="
{{
10
}}
"
padding="
{{
[
0
,
12
,
0
,
12
]
}}
" type="masonry">
<view
v-for=
"(item, index) in cangpinList"
:key=
"index"
class=
"waterfall-item"
@
click=
"handleItemClick_cangpin(item, index)"
>
<view
class=
"item-up-content"
>
<image
class=
"item-image"
:src=
"item.imgUrl"
mode=
"widthFix"
/>
<view
class=
"item-num"
>
<text
class=
"badge-num"
>
N0.
{{
item
.
bizNo
}}
</text>
</view>
<view
v-if=
"item.state == 1"
class=
"item-badge"
>
<text
class=
"badge-text"
>
精选推荐
</text>
</view>
</view>
<view
class=
"item-info"
>
<view
class=
"item-title"
>
{{
item
.
content
}}
</view>
<view
class=
"item-meta"
>
<view
class=
"creator-info"
>
<image
class=
"creator-avatar"
:src=
"item.avatar"
mode=
"aspectFit"
/>
<text
class=
"creator-name"
>
{{
item
.
nickname
}}
</text>
</view>
</view>
</view>
</view>
</grid-view>
</scroll-view>
</view>
<!-- 我的收藏列表 -->
<view
v-if=
"activeSubTab === 'favorites'"
class=
"sub-tab-content"
>
<view
class=
"waterfall-list-noval2"
v-if=
"!(shoucangList && shoucangList.length > 0)"
>
<view
class=
"noval-content"
>
<!-- 卡片插图 -->
<view
class=
"noval-illustration"
>
<image
class=
"noval-img"
:src=
"$baseUrl + `xingmaLab/1001/cangpin_noval_img0.png`"
mode=
"aspectFit"
/>
</view>
<!-- 提示文字 -->
<text
class=
"noval-tip"
>
暂无收藏的藏品哦
</text>
</view>
</view>
<scroll-view
class=
"waterfall-list1"
scroll-y=
"true"
@
scrolltolower=
"handleScrollToLower_shoucang"
v-if=
"shoucangList && shoucangList.length > 0"
>
<grid-view
column=
"2"
main-axis-gap=
"
{{
10
}}
" cross-axis-gap="
{{
10
}}
"
padding="
{{
[
0
,
12
,
0
,
12
]
}}
" type="masonry">
<view
v-for=
"(item, index) in shoucangList"
:key=
"index"
class=
"waterfall-item"
@
click=
"handleItemClick_shoucang(item, index)"
>
<view
class=
"item-up-content"
>
<image
class=
"item-image"
:src=
"item.imgUrl"
mode=
"widthFix"
/>
<view
class=
"item-num"
>
<text
class=
"badge-num"
>
N0.
{{
item
.
bizNo
}}
</text>
</view>
<view
v-if=
"item.state == 1"
class=
"item-badge"
>
<text
class=
"badge-text"
>
精选推荐
</text>
</view>
</view>
<view
class=
"item-info"
>
<view
class=
"item-title"
>
{{
item
.
content
}}
</view>
<view
class=
"item-meta"
>
<view
class=
"creator-info"
>
<image
class=
"creator-avatar"
:src=
"item.avatar"
mode=
"aspectFit"
/>
<text
class=
"creator-name"
>
{{
item
.
nickname
}}
</text>
</view>
</view>
</view>
</view>
</grid-view>
</scroll-view>
</view>
</view>
</view>
<!-- 底部导航 -->
<view
class=
"bottom-navigation"
>
<view
class=
"bottom-nav-item1"
:class=
"
{ active: activeTab === 'cangguan' }"
@click="handleBottomNavClick('cangguan')">
<image
class=
"bottom-nav-icon1"
:src=
"activeTab === 'cangguan' ? $baseUrl + `xingmaLab/1001/tab_cangguang_selected.png` : $baseUrl + `xingmaLab/1001/tab_cangguang_normal.png`"
mode=
"aspectFit"
/>
</view>
<view
class=
"bottom-nav-item2"
>
<image
class=
"publish-icon"
:src=
"$baseUrl + `xingmaLab/1001/tab_fabu.png`"
@
click=
"handleBottomNavFabu"
mode=
"aspectFit"
/>
</view>
<view
class=
"bottom-nav-item3"
:class=
"
{ active: activeTab === 'wodecangguan' }"
@click="handleBottomNavClick('wodecangguan')">
<image
class=
"bottom-nav-icon3"
:src=
"activeTab === 'wodecangguan' ? $baseUrl + `xingmaLab/1001/tab_wodecangguan_selected.png` : $baseUrl + `xingmaLab/1001/tab_wodecangguan_normal.png`"
mode=
"aspectFit"
/>
</view>
</view>
<!-- 无次数弹窗 - 使用 Xingmalabnotimepop 组件 -->
<Xingmalabnotimepop
:visible=
"showNoTimePopup"
title=
"发布次数已用完"
@
button-click=
"handleNoTimeButtonClick"
@
close=
"showNoTimePopup = false"
/>
</view>
</
template
>
<
script
setup
>
import
{
ref
,
onMounted
,
onUnmounted
}
from
'vue'
import
{
fetchRecordList
,
fetchRecordMyrecords
,
fetchFavoriteList
}
from
'../../api/xingmaLab'
import
{
onPageScroll
,
onShow
}
from
"@dcloudio/uni-app"
;
import
{
showLoading
,
hideLoading
,
jump
,
JumpType
}
from
'../../utils/index.js'
import
{
useXingmaLabStore
}
from
'../../stores/xingmaLab'
import
Xingmalabnotimepop
from
'../../components/xingmaLab/Xingmalabnotimepop.vue'
import
md
from
'../../md'
;
// 定义组件名称
defineOptions
({
name
:
'XingmaLab'
})
// 响应式数据
const
activeTab
=
ref
(
'cangguan'
)
const
activeSubTab
=
ref
(
'collections'
)
const
cangguanList
=
ref
([]);
const
cangpinList
=
ref
([]);
const
shoucangList
=
ref
([]);
const
xingmaLabStore
=
useXingmaLabStore
();
// 弹窗显示状态
const
showNoTimePopup
=
ref
(
false
)
// 无次数弹窗
// 收藏列表分页管理
const
shoucangListIdx
=
ref
(
1
);
const
shoucangTotalPage
=
ref
(
0
);
const
currentItemType
=
ref
(
'cangguan'
);
// onPageScroll((e) => {
// console.log('e.scrollTop=',e);
// const newVal = e.scrollTop;
// });
const
isGeting
=
ref
(
false
);
const
handleScroll_cangguan
=
async
(
e
)
=>
{
console
.
log
(
'cangguan_已到底部'
);
if
(
cangguanListIdx
.
value
>
cangguanTotalPage
.
value
-
1
)
return
;
if
(
isGeting
.
value
)
return
;
showLoading
()
isGeting
.
value
=
true
;
cangguanListIdx
.
value
++
;
const
data1
=
await
fetchRecordList
(
cangguanListIdx
.
value
,
4
);
cangguanList
.
value
=
cangguanList
.
value
.
concat
(
data1
.
data
.
list
);
cangguanTotalPage
.
value
=
data1
?.
data
?.
totalPage
;
setTimeout
(()
=>
{
isGeting
.
value
=
false
;
},
500
);
hideLoading
();
}
const
handleScroll1
=
(
e
)
=>
{
console
.
log
(
'e.scrollTop='
,
e
);
}
const
handleScrollToLower_cangpin
=
async
()
=>
{
console
.
log
(
'已到底部'
);
if
(
cangpinListIdx
.
value
>
cangpinTotalPage
.
value
-
1
)
return
;
if
(
isGeting
.
value
)
return
;
showLoading
();
isGeting
.
value
=
true
;
cangpinListIdx
.
value
++
;
const
data2
=
await
fetchRecordMyrecords
(
cangpinListIdx
.
value
,
1
);
cangpinList
.
value
=
cangpinList
.
value
.
concat
(
data2
.
data
.
list
);
cangpinTotalPage
.
value
=
data2
?.
data
?.
totalPage
;
setTimeout
(()
=>
{
isGeting
.
value
=
false
;
},
500
);
hideLoading
();
}
const
handleScrollToLower_shoucang
=
async
()
=>
{
console
.
log
(
'收藏列表已到底部'
);
if
(
shoucangListIdx
.
value
>
shoucangTotalPage
.
value
-
1
)
return
;
if
(
isGeting
.
value
)
return
;
showLoading
();
isGeting
.
value
=
true
;
shoucangListIdx
.
value
++
;
const
data3
=
await
fetchFavoriteList
(
shoucangListIdx
.
value
,
1
);
shoucangList
.
value
=
shoucangList
.
value
.
concat
(
data3
.
data
.
list
);
shoucangTotalPage
.
value
=
data3
?.
data
?.
totalPage
;
setTimeout
(()
=>
{
isGeting
.
value
=
false
;
},
500
);
hideLoading
();
}
const
handleImageLoad
=
(
e
,
item
,
index
)
=>
{
// 获取图片的实际尺寸
const
{
width
,
height
}
=
e
.
detail
;
// 计算图片在360rpx宽度下的实际高度
// 360rpx 转换为 px (假设 1rpx = 0.5px,根据实际设备调整)
const
targetWidth
=
707
;
const
rpxToPx
=
targetWidth
/
width
;
const
targetHeight
=
height
*
rpxToPx
;
item
.
targetWidth
=
targetWidth
;
item
.
targetHeight
=
targetHeight
;
console
.
log
(
`图片
${
index
}
加载完成,设置宽度为:
${
item
.
targetWidth
}
px, 设置高度为:
${
item
.
targetHeight
}
px`
);
}
const
currentItem
=
ref
(
null
);
onShow
(
async
()
=>
{
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab首页"
,
componentName
:
"底部切换组件"
,
componentContent
:
"星妈会藏馆"
});
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab首页"
,
componentName
:
"底部切换组件"
,
componentContent
:
"发布"
});
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab首页"
,
componentName
:
"底部切换组件"
,
componentContent
:
"我的藏品"
});
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab首页"
,
componentName
:
"星妈会藏馆"
,
componentContent
:
"首页藏品"
});
const
pages
=
getCurrentPages
()
let
currentPage
=
pages
[
pages
.
length
-
1
]
const
isFavorite
=
currentPage
?.
properties
?.
isFavorite
console
.
log
(
'isFavorite='
,
isFavorite
);
console
.
log
(
'currentPage='
,
currentPage
);
// console.log('onshow')
//1收藏,-1取消收藏,不存在刷新页面
if
(
!
isFavorite
){
await
xingmaLabStore
.
loadXingmaInfo
();
await
reloadCangguanList
();
await
reloadCangpinList
();
await
reloadShoucangList
();
}
else
{
if
(
isFavorite
==
1
){
currentItem
.
value
.
collection
=
true
;
}
else
{
if
(
currentItemType
.
value
==
'cangguan'
){
currentItem
.
value
.
collection
=
false
;
}
else
{
shoucangList
.
value
.
splice
(
currentItem
.
value
,
1
)
}
}
}
})
const
cangguanListIdx
=
ref
(
1
);
const
cangguanTotalPage
=
ref
(
0
);
const
cangpinListIdx
=
ref
(
1
);
const
cangpinTotalPage
=
ref
(
0
);
onMounted
(
async
()
=>
{
// await xingmaLabStore.loadXingmaInfo();
// console.log('xingmaLabStore=', xingmaLabStore.xingmaInfo);
// //获取藏馆列表
// const data1 = await fetchRecordList(cangguanListIdx.value, 4);
// cangguanList.value = cangguanList.value.concat(data1.data.list);
// cangguanTotalPage.value = data1.data.totalPage;
// //获取我的藏品列表
// const data2 = await fetchRecordMyrecords(cangpinListIdx.value, 8);
// cangpinList.value = cangpinList.value.concat(data2.data.list);
// cangpinTotalPage.value = data2.data.totalPage;
// // cangpinList.value = data.data.list;
// //获取我的收藏列表
// const data3 = await fetchFavoriteList(shoucangListIdx.value, 4);
// shoucangList.value = shoucangList.value.concat(data3.data.list);
// shoucangTotalPage.value = data3.data.totalPage;
// shoucangList.value = data.data.list;
})
// 刷新数据:封装三个列表的刷新方法,供全局事件调用
const
reloadCangguanList
=
async
()
=>
{
showLoading
()
cangguanListIdx
.
value
=
1
;
cangguanList
.
value
=
[];
const
data
=
await
fetchRecordList
(
cangguanListIdx
.
value
,
4
);
cangguanList
.
value
=
data
.
data
.
list
;
cangguanTotalPage
.
value
=
data
.
data
.
totalPage
;
hideLoading
()
}
const
reloadCangpinList
=
async
()
=>
{
showLoading
()
cangpinListIdx
.
value
=
1
;
const
data
=
await
fetchRecordMyrecords
(
cangpinListIdx
.
value
,
8
);
cangpinList
.
value
=
[];
cangpinList
.
value
=
data
.
data
.
list
;
cangpinTotalPage
.
value
=
data
.
data
.
totalPage
;
hideLoading
()
}
const
reloadShoucangList
=
async
()
=>
{
showLoading
()
shoucangListIdx
.
value
=
1
;
shoucangList
.
value
=
[];
const
data
=
await
fetchFavoriteList
(
shoucangListIdx
.
value
,
8
);
shoucangList
.
value
=
data
.
data
.
list
;
shoucangTotalPage
.
value
=
data
.
data
.
totalPage
;
hideLoading
()
}
// 监听其他页面派发的全局事件
const
handleGlobalRefresh
=
async
(
payload
)
=>
{
console
.
log
(
'收到全局刷新事件 xingmaLab:refresh,payload='
,
payload
)
// 可根据 payload.type 刷新指定列表,这里默认全部刷新
await
Promise
.
all
([
reloadCangguanList
(),
reloadCangpinList
(),
reloadShoucangList
()
])
}
// uni.$emit('xingmaLab:refresh', { type: 'all' }) // or type: 'cangpin' | 'shoucang' | 'cangguan'
// onMounted(() => {
// uni.$on('xingmaLab:refresh', handleGlobalRefresh)
// })
// onUnmounted(() => {
// uni.$off('xingmaLab:refresh', handleGlobalRefresh)
// })
const
convertDobuleList
=
(
list
)
=>
{
let
newList
=
[];
newList
.
push
([]);
newList
.
push
([]);
for
(
let
i
=
0
;
i
<
list
.
length
;
i
++
)
{
if
(
i
%
2
==
0
)
{
newList
[
0
].
push
(
list
[
i
]);
}
else
{
newList
[
1
].
push
(
list
[
i
]);
}
}
return
newList
;
}
// 方法
const
handleBack
=
()
=>
{
uni
.
navigateBack
({
delta
:
1
})
}
const
switchTab
=
(
tab
)
=>
{
activeTab
.
value
=
tab
if
(
tab
===
'wodecangguan'
)
{
activeSubTab
.
value
=
'collections'
}
}
//我的藏品/我的收藏tab
const
switchSubTab
=
async
(
subTab
)
=>
{
if
(
subTab
==
'collections'
){
if
(
currentFrontNavType
!=
'collections'
){
currentFrontNavType
=
'collections'
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"星妈lab首页"
,
componentName
:
"我的藏品"
,
componentContent
:
"我的藏品-我的藏品"
});
// await reloadCangpinList();
//走onshow刷新,因为去发布按钮埋点
}
}
else
if
(
subTab
==
'favorites'
){
if
(
currentFrontNavType
!=
'favorites'
){
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"星妈lab首页"
,
componentName
:
"我的藏品"
,
componentContent
:
"我的藏品-我的收藏"
});
currentFrontNavType
=
'favorites'
await
reloadShoucangList
();
}
}
activeSubTab
.
value
=
subTab
// if(currentFrontNavType == 'collections'){
// await reloadCangguanList();
// }else{
// await reloadShoucangList();
// }
}
const
handleBottomNavFabu
=
()
=>
{
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"星妈lab首页"
,
componentName
:
"底部切换组件"
,
componentContent
:
"发布"
});
console
.
log
(
'showNoTimePopup 变量状态:'
,
showNoTimePopup
)
console
.
log
(
'xingmaLabStore.xingmaInfo:'
,
xingmaLabStore
.
xingmaInfo
)
if
(
xingmaLabStore
.
xingmaInfo
&&
xingmaLabStore
.
xingmaInfo
.
isReachedLimit
)
{
console
.
log
(
'已达到发布上线'
)
// 显示无次数弹窗
showNoTimePopup
.
value
=
true
console
.
log
(
'弹窗状态已设置为:'
,
showNoTimePopup
.
value
)
}
else
{
console
.
log
(
'跳转发布页面'
)
uni
.
navigateTo
({
url
:
'/pages/XingmaLabPublishPage/XingmaLabPublishPage'
})
}
}
let
currentButtomNavType
=
'cangguan'
;
let
currentFrontNavType
=
''
;
// 底部导航点击处理
const
handleBottomNavClick
=
async
(
navType
)
=>
{
if
(
navType
==
'cangguan'
)
{
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"星妈lab首页"
,
componentName
:
"底部切换组件"
,
componentContent
:
"星妈会藏馆"
});
// 点击"星妈会藏馆"时,切换到藏馆tab,展示单列列表
activeTab
.
value
=
'cangguan'
if
(
currentButtomNavType
!=
'cangguan'
){
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab首页"
,
componentName
:
"星妈会藏馆"
,
componentContent
:
"首页藏品"
});
currentButtomNavType
=
'cangguan'
await
reloadCangguanList
();
}
}
else
if
(
navType
==
'wodecangguan'
)
{
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"星妈lab首页"
,
componentName
:
"底部切换组件"
,
componentContent
:
"我的藏品"
});
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab-我的藏品页"
,
componentName
:
"我的藏品"
,
componentContent
:
"我的藏品-藏品标题"
});
// 点击"我的藏品"时,切换到我的藏馆tab,默认展示我的藏品
activeTab
.
value
=
'wodecangguan'
if
(
currentButtomNavType
!=
'wodecangguan'
){
currentButtomNavType
=
'wodecangguan'
;
if
(
currentFrontNavType
==
''
){
if
(
!
(
cangpinList
.
value
&&
cangpinList
.
value
.
length
>
0
)){
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab-我的藏品页"
,
componentName
:
"我的藏品"
,
componentContent
:
"我的藏品-去发布"
});
}
// else{
// md.sensorComponentLogTake({
// xcxComponentExposure: "true",
// pageName: "星妈lab-我的藏品页",
// componentName: "我的藏品",
// componentContent: "我的藏品-我的藏品"
// });
// }
activeSubTab
.
value
=
'collections'
currentFrontNavType
=
'collections'
// await reloadCangpinList();
}
else
{
currentFrontNavType
=
activeSubTab
.
value
;
if
(
activeSubTab
.
value
==
'collections'
){
if
(
!
(
cangpinList
.
value
&&
cangpinList
.
value
.
length
>
0
)){
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"星妈lab-我的藏品页"
,
componentName
:
"我的藏品"
,
componentContent
:
"我的藏品-去发布"
});
}
// else{
// md.sensorComponentLogTake({
// xcxComponentExposure: "true",
// pageName: "星妈lab-我的藏品页",
// componentName: "我的藏品",
// componentContent: "我的藏品-我的藏品"
// });
// }
// await reloadCangpinList();
//走onshow刷新,因为去发布按钮埋点
}
else
{
// md.sensorComponentLogTake({
// xcxComponentExposure: "true",
// pageName: "星妈lab-我的藏品页",
// componentName: "我的藏品",
// componentContent: "我的藏品-我的收藏"
// });
await
reloadShoucangList
();
}
}
}
}
}
const
handleItemClick_cangguan
=
(
item
,
index
)
=>
{
console
.
log
(
'点击了项目藏馆:'
,
item
)
currentItem
.
value
=
item
;
currentItemType
.
value
=
'cangguan'
;
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"星妈lab首页"
,
componentName
:
"星妈会藏馆"
,
componentContent
:
`首页藏品-藏品标题
${
item
.
content
}
`
});
// 这里可以添加跳转逻辑
uni
.
navigateTo
({
url
:
'/pages/XingmaLabDetailPage/XingmaLabDetailPage?id='
+
item
.
id
+
'&index='
+
index
})
}
const
handleItemClick_cangpin
=
(
item
,
index
)
=>
{
console
.
log
(
'点击了项目藏品:'
,
item
)
// currentItem.value = item;
// 这里可以添加跳转逻辑
uni
.
navigateTo
({
url
:
'/pages/XingmaLabDetailPage/XingmaLabDetailPage?id='
+
item
.
id
+
'&index='
+
index
})
}
const
handleItemClick_shoucang
=
(
item
,
index
)
=>
{
currentItem
.
value
=
index
;
currentItemType
.
value
=
'shoucang'
;
console
.
log
(
'点击了项目收藏:'
,
item
)
// 这里可以添加跳转逻辑
// currentItem.value = item;
uni
.
navigateTo
({
url
:
'/pages/XingmaLabDetailPage/XingmaLabDetailPage?id='
+
item
.
id
+
'&index='
+
index
})
}
const
handlePublish
=
()
=>
{
console
.
log
(
'点击了发布按钮'
)
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"星妈lab-我的藏品页"
,
componentName
:
"我的藏品"
,
componentContent
:
"我的藏品-去发布"
});
// 这里可以添加发布逻辑或跳转
if
(
xingmaLabStore
.
xingmaInfo
&&
xingmaLabStore
.
xingmaInfo
.
isReachedLimit
)
{
console
.
log
(
'已达到发布上线'
)
// 显示无次数弹窗
showNoTimePopup
.
value
=
true
console
.
log
(
'弹窗状态已设置为:'
,
showNoTimePopup
.
value
)
}
else
{
console
.
log
(
'跳转发布页面'
)
uni
.
navigateTo
({
url
:
'/pages/XingmaLabPublishPage/XingmaLabPublishPage'
})
}
}
// 无次数弹窗按钮点击处理
const
handleNoTimeButtonClick
=
()
=>
{
showNoTimePopup
.
value
=
false
// // 显示更详细的发布次数信息
// const { currentMonthPublishCount, maxPublishCount, remainingPublishCount } = xingmaLabStore.xingmaInfo
// uni.showToast({
// title: `本月已发布${currentMonthPublishCount}次,剩余${remainingPublishCount}次`,
// icon: 'none',
// duration: 3000
// })
}
</
script
>
<
style
lang=
"less"
scoped
>
@import './xingmaLab.less';
</
style
>
\ No newline at end of file
stores/xingmaLab.js
0 → 100644
View file @
fc9295c6
import
{
defineStore
}
from
"pinia"
;
import
{
fetchRecordIndex
,
fetchRecordList
,
fetchFavoriteList
,
fetchRecordMyrecords
}
from
"../api/xingmaLab.js"
;
export
const
useXingmaLabStore
=
defineStore
(
"xingmaLab"
,
{
state
:
()
=>
{
return
{
// 星妈Lab接口返回的完整数据
xingmaInfo
:
null
,
// 藏馆接口返回的完整数据
cangguanInfo
:
null
,
// 收藏接口返回的完整数据
shoucangInfo
:
null
,
// 藏品接口返回的完整数据
cangpinInfo
:
null
,
// 加载状态(各接口独立)
isLoadingIndex
:
false
,
isLoadingCangguan
:
false
,
isLoadingShoucang
:
false
,
isLoadingCangpin
:
false
,
};
},
actions
:
{
/**
* 获取星妈Lab数据
*/
async
loadXingmaInfo
()
{
try
{
this
.
isLoadingIndex
=
true
;
const
{
data
}
=
await
fetchRecordIndex
();
console
.
log
(
"xingmaInfo data"
,
data
);
if
(
data
)
{
this
.
xingmaInfo
=
data
;
console
.
log
(
'保存的星妈Lab数据:'
,
this
.
xingmaInfo
);
}
else
{
console
.
log
(
'星妈Lab数据格式不正确:'
,
data
);
}
}
catch
(
error
)
{
console
.
log
(
'获取星妈Lab数据失败:'
,
error
);
}
finally
{
this
.
isLoadingIndex
=
false
;
}
},
/**
* 获取藏馆数据
*/
async
loadCangguanInfo
(
pageIndex
=
1
,
pageSize
=
4
)
{
try
{
this
.
isLoadingCangguan
=
true
;
const
{
data
}
=
await
fetchRecordList
(
pageIndex
,
pageSize
);
console
.
log
(
"cangguanInfo data"
,
data
);
if
(
data
)
{
this
.
cangguanInfo
=
data
;
console
.
log
(
'保存的藏馆数据:'
,
this
.
cangguanInfo
);
}
else
{
console
.
log
(
'藏馆数据格式不正确:'
,
data
);
}
}
catch
(
error
)
{
console
.
log
(
'获取藏馆数据失败:'
,
error
);
}
finally
{
this
.
isLoadingCangguan
=
false
;
}
},
/**
* 获取收藏数据
*/
async
loadShoucangInfo
(
pageIndex
=
1
,
pageSize
=
4
)
{
try
{
this
.
isLoadingShoucang
=
true
;
const
{
data
}
=
await
fetchFavoriteList
(
pageIndex
,
pageSize
);
console
.
log
(
"shoucangInfo data"
,
data
);
if
(
data
)
{
this
.
shoucangInfo
=
data
;
console
.
log
(
'保存的收藏数据:'
,
this
.
shoucangInfo
);
}
else
{
console
.
log
(
'收藏数据格式不正确:'
,
data
);
}
}
catch
(
error
)
{
console
.
log
(
'获取收藏数据失败:'
,
error
);
}
finally
{
this
.
isLoadingShoucang
=
false
;
}
},
/**
* 获取藏品数据
*/
async
loadCangpinInfo
(
pageIndex
=
1
,
pageSize
=
8
)
{
try
{
this
.
isLoadingCangpin
=
true
;
const
{
data
}
=
await
fetchRecordMyrecords
(
pageIndex
,
pageSize
);
console
.
log
(
"cangpinInfo data"
,
data
);
if
(
data
)
{
this
.
cangpinInfo
=
data
;
console
.
log
(
'保存的藏品数据:'
,
this
.
cangpinInfo
);
}
else
{
console
.
log
(
'藏品数据格式不正确:'
,
data
);
}
}
catch
(
error
)
{
console
.
log
(
'获取藏品数据失败:'
,
error
);
}
finally
{
this
.
isLoadingCangpin
=
false
;
}
},
/**
* 重置星妈Lab数据
*/
resetXingmaInfo
()
{
this
.
xingmaInfo
=
null
;
},
/**
* 重置藏馆数据
*/
resetCangguanInfo
()
{
this
.
cangguanInfo
=
null
;
},
/**
* 重置收藏数据
*/
resetShoucangInfo
()
{
this
.
shoucangInfo
=
null
;
},
/**
* 重置藏品数据
*/
resetCangpinInfo
()
{
this
.
cangpinInfo
=
null
;
},
/**
* 获取星妈Lab数据
*/
getXingmaInfo
()
{
return
this
.
xingmaInfo
;
},
/**
* 获取藏馆数据
*/
getCangguanInfo
()
{
return
this
.
cangguanInfo
;
},
/**
* 获取收藏数据
*/
getShoucangInfo
()
{
return
this
.
shoucangInfo
;
},
/**
* 获取藏品数据
*/
getCangpinInfo
()
{
return
this
.
cangpinInfo
;
},
},
});
views/Integral.vue
View file @
fc9295c6
...
...
@@ -1726,7 +1726,12 @@ import ShengriliTipPanel from '../components/quanyi/shengriliTipPanel.vue';
mdMap
.
value
.
push
(
'积分服务页-首屏'
);
}
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"积分服务页"
,
componentName
:
"等级卡牌"
,
componentContent
:
"查看升级攻略"
}
);
const
{
data
}
=
await
fetchIntegralJSON
();
integralData
.
value
=
{...
data
}
;
...
...
@@ -1770,6 +1775,27 @@ import ShengriliTipPanel from '../components/quanyi/shengriliTipPanel.vue';
hideLoading
();
initExposure
();
//曝光埋点累计积分
if
(
memberInfo
.
value
.
grade
==
0
&&
!
memberInfo
.
value
.
orderUpgrade
&&
points
.
value
>=
1
){
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"积分服务页"
,
componentName
:
"等级卡牌"
,
componentContent
:
"累计积分"
}
);
}
if
(
getHuangjinMaxVal
()[
memberInfo
.
value
.
grade
]
!=
-
1
&&
!
(
memberInfo
.
value
.
grade
==
0
&&
!
memberInfo
.
value
.
orderUpgrade
&&
points
.
value
>=
1
)){
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"积分服务页"
,
componentName
:
"等级卡牌"
,
componentContent
:
"累计积分"
}
);
}
}
);
const
initExposure
=
()
=>
{
...
...
@@ -1838,7 +1864,9 @@ import ShengriliTipPanel from '../components/quanyi/shengriliTipPanel.vue';
willExpiredPoints
.
value
=
memberInfo
.
value
.
willExpiredPoints
;
nextGradeScoreRuleMin
.
value
=
memberInfo
.
value
.
nextGradeScoreRuleMin
;
vipLevel
.
value
=
memberInfo
.
value
.
grade
;
points
.
value
=
memberInfo
.
value
.
points
;
// points.value = memberInfo.value.points;
points
.
value
=
memberInfo
.
value
.
recentAnnualPointsTotal
;
gradeList
.
value
=
memberInfo
.
value
.
gradeList
;
if
(
memberInfo
.
value
.
memberId
==
"not_login"
){
...
...
@@ -1848,6 +1876,8 @@ import ShengriliTipPanel from '../components/quanyi/shengriliTipPanel.vue';
}
if
(
islogin
.
value
){
vipCardMd
(
vipLevel
.
value
);
nickName
.
value
=
memberInfo
.
value
.
memberName
;
// 清空之前的数据
// vipLvDatas.value = [];//??????????
...
...
@@ -1878,6 +1908,45 @@ import ShengriliTipPanel from '../components/quanyi/shengriliTipPanel.vue';
}
const
vipCardMd
=
(
vipLevel
,
isExposure
=
true
)
=>
{
if
(
isExposure
){
md
.
sensorComponentLogTake
({
xcxComponentExposure
:
"true"
,
pageName
:
"积分服务页"
,
componentName
:
"等级卡牌"
,
componentContent
:
"等级卡牌点击"
+
lvNameMd
(
vipLevel
)
}
);
}
else
{
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"积分服务页"
,
componentName
:
"等级卡牌"
,
componentContent
:
"等级卡牌点击"
+
lvNameMd
(
vipLevel
)
}
);
}
}
const
lvNameMd
=
(
lv
)
=>
{
switch
(
Number
(
lv
)){
case
0
:
return
'V1黄金会员'
;
break
;
case
1
:
return
'V2铂金会员'
;
break
;
case
2
:
return
'V3钻石会员'
;
break
;
case
3
:
return
'V4星光会员'
;
break
;
case
4
:
return
'V5星耀会员'
;
break
;
}
}
//banner点击事件
const
bannerHandler
=
(
item
,
index
)
=>
{
let
buttonName
=
''
;
...
...
@@ -1922,6 +1991,13 @@ import ShengriliTipPanel from '../components/quanyi/shengriliTipPanel.vue';
buttonName
:
"攻略"
,
}
);
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"积分服务页"
,
componentName
:
"等级卡牌"
,
componentContent
:
"查看升级攻略"
}
);
gotoGonglue
();
// const url = vipIntegral.value.gonglue.url;
// const type = vipIntegral.value.gonglue.type;
...
...
@@ -1974,6 +2050,13 @@ import ShengriliTipPanel from '../components/quanyi/shengriliTipPanel.vue';
buttonName
:
"积分明细"
,
}
);
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"积分服务页"
,
componentName
:
"等级卡牌"
,
componentContent
:
"累计积分"
}
);
const
url
=
vipIntegral
.
value
.
jifenmingxi
.
url
.
replace
(
"{crmid
}
"
,
memberInfo
.
value
.
memberId
);
const
type
=
vipIntegral
.
value
.
jifenmingxi
.
type
;
console
.
log
(
'积分明细链接:=='
,
url
)
...
...
@@ -2062,6 +2145,15 @@ import ShengriliTipPanel from '../components/quanyi/shengriliTipPanel.vue';
const
currentIndex
=
e
.
detail
.
current
;
// console.log('当前swiper-item索引:', currentIndex);
itemIndex
.
value
=
currentIndex
;
md
.
sensorComponentLogTake
({
xcxComponentClick
:
"true"
,
pageName
:
"积分服务页"
,
componentName
:
"等级卡牌"
,
componentContent
:
"等级卡牌切换"
}
);
vipCardMd
(
currentIndex
);
// 获取当前滚动位置
// const scrollLeft = e.detail.scrollLeft;
// const directionVal = ref(0.3);
...
...
@@ -2380,6 +2472,7 @@ import ShengriliTipPanel from '../components/quanyi/shengriliTipPanel.vue';
return
;
}
vipCardMd
(
vipLevel
.
value
,
false
);
const
item
=
vipIntegral
.
value
.
vipCardInfo
;
if
(
item
.
url
==
""
){
return
;
...
...
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