Commit fc9295c6 authored by 张九刚's avatar 张九刚

Merge branch 'master' into feature/20250901_share

parents 58fc3df5 27e1aa78
File added
unpackage/
dist/
static/
node_modules/
.DS_Store
\ No newline at end of file
// {
// // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/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" : [
......
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)
......@@ -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')}`
});
}
}
......
# 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)
# 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.2s 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 版本完全一致
<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>
<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
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
}
<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>
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`
}
}
{
"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": {},
"type": 3,
"url": "https://mp.weixin.qq.com/s/HhBF5h8xX8zOrthsy2-Y-A"
"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"
},
"bgUrl": "homepage/content_4.png"
}],
{
"_style": "width:263rpx;height: 324rpx;right: 40rpx;top: 1120rpx;",
"link": {
"extra": {},
"type": 3,
"url": "https://mp.weixin.qq.com/s/HhBF5h8xX8zOrthsy2-Y-A"
},
"bgUrl": "homepage/content_4.png"
}
],
"toolList": {
"maintitle": "工具推荐",
"jtIcon": "homepage/tool_jt.png",
"subtitle": "更多妈妈都在用,告别手忙脚乱,助你轻松带娃!",
"tools": [{
"icon": "homepage/tool_icon_2.png",
"link": {
"extra": {},
"tools": [
{
"icon": "homepage/tool_icon_2.png",
"link": {
"extra": {},
"type": 1,
"url": "/pages/feedingIndex/feedingIndex"
},
"context": "一键更新喂养记录",
"type": 1,
"url": "/pages/feedingIndex/feedingIndex"
},
"context": "一键更新喂养记录",
"type": 1,
"title": "喂养工具"
}, {
"icon": "homepage/tool_icon_3.png",
"link": {
"extra": {},
"title": "喂养工具"
},
{
"icon": "homepage/tool_icon_3.png",
"link": {
"extra": {},
"type": 1,
"url": "/pages/postnatalCheckUp/postnatalCheckUp"
},
"context": "孕周检查准时告知",
"type": 1,
"url": "/pages/postnatalCheckUp/postnatalCheckUp"
},
"context": "孕周检查准时告知",
"type": 1,
"title": "产检提醒"
}, {
"icon": "homepage/tool_icon_4.png",
"link": {
"extra": {},
"title": "产检提醒"
},
{
"icon": "homepage/tool_icon_4.png",
"link": {
"extra": {},
"type": 1,
"url": "/pages/shengzhangTools/shengzhangTools"
},
"context": "发育偏离预警早报",
"type": 1,
"url": "/pages/shengzhangTools/shengzhangTools"
},
"context": "发育偏离预警早报",
"type": 1,
"title": "宝宝生长测评"
}, {
"icon": "homepage/tool_icon_6.png",
"link": {
"extra": {},
"type": 3,
"url": "https://ali.xudankeji.com/play/rCeXjMai"
},
"context": "测体质选奶粉",
"type": 1,
"title": "体质测试"
}, {
"icon": "homepage/tool_icon_1.png",
"link": {
"extra": {},
"title": "宝宝生长测评"
},
{
"icon": "homepage/tool_icon_6.png",
"link": {
"extra": {},
"type": 3,
"url": "https://ali.xudankeji.com/play/rCeXjMai"
},
"context": "测体质选奶粉",
"type": 1,
"url": "/pages/naming/naming"
},
"context": "AI生成吉利好名",
"type": 1,
"title": "星妈起名"
}],
"title": "体质测试"
},
{
"icon": "homepage/tool_icon_1.png",
"link": {
"extra": {},
"type": 1,
"url": "/pages/naming/naming"
},
"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,469 +119,520 @@
}
},
"channelTabListMianTitle": "有声频道",
"swiperList": [{
"img": "homepage/homeSwiper/V1/7.jpg",
"link": {
"extra": {},
"swiperList": [
{
"img": "homepage/homeSwiper/V1/7.jpg",
"link": {
"extra": {},
"type": 1,
"url": "/pages/syWebview/syWebview?p=xmh09"
},
"type": 1,
"url": "/pages/syWebview/syWebview?p=xmh09"
"title": "北纬47°鲜活溯源之旅",
"url": "homepage/homeSwiper/V1/7.jpg"
},
"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"
{
"videoUrl": "homepage/homeSwiper/V1/8.mp4",
"link": {},
"title": "先是自己再是妈妈",
"url": "homepage/homeSwiper/V1/8.png"
},
"title": "28会员日",
"url": "homepage/homeSwiper/V1/28会员日.jpg"
}],
{
"videoUrl": "homepage/homeSwiper/V1/2.m4v",
"link": {},
"title": "成为妈妈更懂妈妈",
"url": "homepage/homeSwiper/V1/2.png"
}
],
"childrenInfoList": [
[{
"desc2": "乙肝母婴传播可防可控,但“时间窗口”不容错过!",
"link": {
"extra": {},
"type": 3,
"url": "https://mp.weixin.qq.com/s/8OHpMdvbuwJPGsfdXs7aDg"
},
"isNew": false,
"desc": "新生儿出生后24小时必做!错过可能影响一生健康",
"bgUrl": "homepage/children/childrenV1/1.jpg"
}, {
"desc2": "家长通过科学抚触,不仅能激活宝宝大脑神经突触,还能为宝宝的认知力、自护力打下坚实基础。",
"link": {
"extra": {},
"type": 3,
"url": "https://mp.weixin.qq.com/s/vMyPcDbAmwMsZCMlW0kkDA"
},
"isNew": false,
"desc": "0-3岁宝宝触觉发育关键期,附按摩手法!",
"bgUrl": "homepage/children/childrenV1/2.jpg"
}, {
"desc2": "究竟是体质虚弱?生病了?还是缺乏某些营养元素呢?星妈会带你一次性搞懂宝宝出汗的秘密!",
"link": {
"extra": {},
"type": 3,
"url": "https://mp.weixin.qq.com/s/pnYVG4yTuBSbNN-fIYKrCQ"
},
"isNew": false,
"desc": "宝宝满头汗vs全身湿!小心这4种疾病,正在偷走健康!",
"bgUrl": "homepage/children/childrenV1/3.jpg"
}]
[
{
"desc2": "乙肝母婴传播可防可控,但“时间窗口”不容错过!",
"link": {
"extra": {},
"type": 3,
"url": "https://mp.weixin.qq.com/s/8OHpMdvbuwJPGsfdXs7aDg"
},
"isNew": false,
"desc": "新生儿出生后24小时必做!错过可能影响一生健康",
"bgUrl": "homepage/children/childrenV1/1.jpg"
},
{
"desc2": "家长通过科学抚触,不仅能激活宝宝大脑神经突触,还能为宝宝的认知力、自护力打下坚实基础。",
"link": {
"extra": {},
"type": 3,
"url": "https://mp.weixin.qq.com/s/vMyPcDbAmwMsZCMlW0kkDA"
},
"isNew": false,
"desc": "0-3岁宝宝触觉发育关键期,附按摩手法!",
"bgUrl": "homepage/children/childrenV1/2.jpg"
},
{
"desc2": "究竟是体质虚弱?生病了?还是缺乏某些营养元素呢?星妈会带你一次性搞懂宝宝出汗的秘密!",
"link": {
"extra": {},
"type": 3,
"url": "https://mp.weixin.qq.com/s/pnYVG4yTuBSbNN-fIYKrCQ"
},
"isNew": false,
"desc": "宝宝满头汗vs全身湿!小心这4种疾病,正在偷走健康!",
"bgUrl": "homepage/children/childrenV1/3.jpg"
}
]
],
"vipConfigList": [{
"btnTitle": "首注200元优惠券",
"subTitle": "新人礼权益",
"level": "注册会员",
"btnSubTitle": "立即注册",
"grade": "-1",
"bgUrl": "homepage/cardbg1.png"
}, {
"btnTitle": "三甲医生在线问诊",
"subTitle": "免费问诊权益",
"btnSubTitle": "立即了解",
"grade": "0",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
"vipConfigList": [
{
"btnTitle": "首注200元优惠券",
"subTitle": "新人礼权益",
"level": "注册会员",
"btnSubTitle": "立即注册",
"grade": "-1",
"bgUrl": "homepage/cardbg1.png"
},
"bgUrl": "homepage/cardbg1.png"
}, {
"btnTitle": "12类系列课程",
"subTitle": "育儿课程权益",
"btnSubTitle": "立即了解",
"grade": "1",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
{
"btnTitle": "三甲医生在线问诊",
"subTitle": "免费问诊权益",
"btnSubTitle": "立即了解",
"grade": "0",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
},
"bgUrl": "homepage/cardbg1.png"
},
"bgUrl": "homepage/cardbg1.png"
}, {
"btnTitle": "12类系列课程",
"subTitle": "育儿课程权益",
"btnSubTitle": "立即了解",
"grade": "2",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
{
"btnTitle": "12类系列课程",
"subTitle": "育儿课程权益",
"btnSubTitle": "立即了解",
"grade": "1",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
},
"bgUrl": "homepage/cardbg1.png"
},
"bgUrl": "homepage/cardbg1.png"
}, {
"btnTitle": "1分购、优惠券",
"subTitle": "月月礼权益",
"btnSubTitle": "立即了解",
"grade": "3",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
{
"btnTitle": "12类系列课程",
"subTitle": "育儿课程权益",
"btnSubTitle": "立即了解",
"grade": "2",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
},
"bgUrl": "homepage/cardbg1.png"
},
"bgUrl": "homepage/cardbg1.png"
}, {
"btnTitle": "1分购、优惠券",
"subTitle": "月月礼权益",
"btnSubTitle": "立即了解",
"grade": "4",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
{
"btnTitle": "1分购、优惠券",
"subTitle": "月月礼权益",
"btnSubTitle": "立即了解",
"grade": "3",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
},
"bgUrl": "homepage/cardbg1.png"
},
"bgUrl": "homepage/cardbg1.png"
}],
{
"btnTitle": "1分购、优惠券",
"subTitle": "月月礼权益",
"btnSubTitle": "立即了解",
"grade": "4",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
},
"bgUrl": "homepage/cardbg1.png"
}
],
"changelInfoList": [
[{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=22101&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "凯叔·金子美铃童诗:【藏好了吗】",
"bgUrl": "homepage/channel/soundChannelV1/1/1.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=22102&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "凯叔·金子美铃童诗:【水和风和娃娃】",
"bgUrl": "homepage/channel/soundChannelV1/1/2.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=22103&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "凯叔·金子美铃童诗:【羽绒被】",
"bgUrl": "homepage/channel/soundChannelV1/1/3.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=22104&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "凯叔·金子美铃童诗:【知了的外衣】",
"bgUrl": "homepage/channel/soundChannelV1/1/4.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=22106&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "凯叔·金子美铃童诗:【风】",
"bgUrl": "homepage/channel/soundChannelV1/1/5.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=22107&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "凯叔·金子美铃童诗:【我和小鸟和铃铛】",
"bgUrl": "homepage/channel/soundChannelV1/1/6.jpg"
}],
[{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21891&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "培养宝宝不虚荣的好品格:【红舞鞋】",
"bgUrl": "homepage/channel/soundChannelV1/2/1.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21845&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "【动物王国】教宝宝学会爱护东西:【谁是破坏王】",
"bgUrl": "homepage/channel/soundChannelV1/2/2.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21930&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "培养宝宝拒绝的勇气:【该说不,就说不】",
"bgUrl": "homepage/channel/soundChannelV1/2/3.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21898&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "培养宝宝专心的好习惯:【两个青年学棋】",
"bgUrl": "homepage/channel/soundChannelV1/2/4.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21953&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "培养宝宝坚持的好品格:【不怕挫折的渔夫】",
"bgUrl": "homepage/channel/soundChannelV1/2/5.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21840&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "培养宝宝的自制力:【一次只要一个】",
"bgUrl": "homepage/channel/soundChannelV1/2/6.jpg"
}],
[{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/calendar/parentchildsongsdetail?id=22281"
},
"desc": "营养健康小知识:营养元素钙铁锌",
"bgUrl": "homepage/channel/soundChannelV1/3/1.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21328&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "宝宝指甲长倒刺是缺维生素吗?",
"bgUrl": "homepage/channel/soundChannelV1/3/2.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21545&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "如何分辨宝宝是攒肚还是便秘?",
"bgUrl": "homepage/channel/soundChannelV1/3/3.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21310&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "手足口疫苗有必要打吗?",
"bgUrl": "homepage/channel/soundChannelV1/3/4.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21734&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "宝宝多大开始刷牙?一定不能晚于这个时间!",
"bgUrl": "homepage/channel/soundChannelV1/3/5.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=25897&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "如何缓解0-6月宝宝肠绞痛?",
"bgUrl": "homepage/channel/soundChannelV1/3/6.jpg"
}],
[{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21533&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "如何拯救睡渣宝宝?培养自主入睡?",
"bgUrl": "homepage/channel/soundChannelV1/4/1.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21602&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "开灯睡觉影响宝宝智力发育?",
"bgUrl": "homepage/channel/soundChannelV1/4/2.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21613&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "宝宝都爱“投降式睡姿”?要纠正吗?",
"bgUrl": "homepage/channel/soundChannelV1/4/3.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21494&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "娃睡得正香,要不要叫醒吃奶?",
"bgUrl": "homepage/channel/soundChannelV1/4/4.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21633&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "宝宝总夜醒怎么办?",
"bgUrl": "homepage/channel/soundChannelV1/4/5.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21629&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "宝宝每天睡多久合适?",
"bgUrl": "homepage/channel/soundChannelV1/4/6.jpg"
}],
[{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21357&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "宝宝夏日拉肚子该怎么办?",
"bgUrl": "homepage/channel/soundChannelV1/5/1.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21497&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "给宝宝冲奶粉,冲稀点不上火,浓点更营养?",
"bgUrl": "homepage/channel/soundChannelV1/5/2.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21506&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "怎样辨别奶粉中含有香精?",
"bgUrl": "homepage/channel/soundChannelV1/5/3.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21455&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "怎样判断宝宝吃饱了没?",
"bgUrl": "homepage/channel/soundChannelV1/5/4.jpg"
}, {
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21495&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "奶粉颜色偏黄好?还是偏白好?",
"bgUrl": "homepage/channel/soundChannelV1/5/5.jpg"
}, {
[
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=22101&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "凯叔·金子美铃童诗:【藏好了吗】",
"bgUrl": "homepage/channel/soundChannelV1/1/1.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=22102&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "凯叔·金子美铃童诗:【水和风和娃娃】",
"bgUrl": "homepage/channel/soundChannelV1/1/2.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=22103&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "凯叔·金子美铃童诗:【羽绒被】",
"bgUrl": "homepage/channel/soundChannelV1/1/3.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=22104&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "凯叔·金子美铃童诗:【知了的外衣】",
"bgUrl": "homepage/channel/soundChannelV1/1/4.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=22106&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "凯叔·金子美铃童诗:【风】",
"bgUrl": "homepage/channel/soundChannelV1/1/5.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=22107&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "凯叔·金子美铃童诗:【我和小鸟和铃铛】",
"bgUrl": "homepage/channel/soundChannelV1/1/6.jpg"
}
],
[
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21891&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "培养宝宝不虚荣的好品格:【红舞鞋】",
"bgUrl": "homepage/channel/soundChannelV1/2/1.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21845&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "【动物王国】教宝宝学会爱护东西:【谁是破坏王】",
"bgUrl": "homepage/channel/soundChannelV1/2/2.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21930&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "培养宝宝拒绝的勇气:【该说不,就说不】",
"bgUrl": "homepage/channel/soundChannelV1/2/3.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21898&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "培养宝宝专心的好习惯:【两个青年学棋】",
"bgUrl": "homepage/channel/soundChannelV1/2/4.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21953&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "培养宝宝坚持的好品格:【不怕挫折的渔夫】",
"bgUrl": "homepage/channel/soundChannelV1/2/5.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21840&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "培养宝宝的自制力:【一次只要一个】",
"bgUrl": "homepage/channel/soundChannelV1/2/6.jpg"
}
],
[
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/calendar/parentchildsongsdetail?id=22281"
},
"desc": "营养健康小知识:营养元素钙铁锌",
"bgUrl": "homepage/channel/soundChannelV1/3/1.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21328&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "宝宝指甲长倒刺是缺维生素吗?",
"bgUrl": "homepage/channel/soundChannelV1/3/2.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21545&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "如何分辨宝宝是攒肚还是便秘?",
"bgUrl": "homepage/channel/soundChannelV1/3/3.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21310&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "手足口疫苗有必要打吗?",
"bgUrl": "homepage/channel/soundChannelV1/3/4.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21734&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "宝宝多大开始刷牙?一定不能晚于这个时间!",
"bgUrl": "homepage/channel/soundChannelV1/3/5.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=25897&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "如何缓解0-6月宝宝肠绞痛?",
"bgUrl": "homepage/channel/soundChannelV1/3/6.jpg"
}
],
[
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21533&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "如何拯救睡渣宝宝?培养自主入睡?",
"bgUrl": "homepage/channel/soundChannelV1/4/1.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21602&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "开灯睡觉影响宝宝智力发育?",
"bgUrl": "homepage/channel/soundChannelV1/4/2.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21613&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "宝宝都爱“投降式睡姿”?要纠正吗?",
"bgUrl": "homepage/channel/soundChannelV1/4/3.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21494&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "娃睡得正香,要不要叫醒吃奶?",
"bgUrl": "homepage/channel/soundChannelV1/4/4.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21633&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "宝宝总夜醒怎么办?",
"bgUrl": "homepage/channel/soundChannelV1/4/5.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21629&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "宝宝每天睡多久合适?",
"bgUrl": "homepage/channel/soundChannelV1/4/6.jpg"
}
],
[
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21357&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "宝宝夏日拉肚子该怎么办?",
"bgUrl": "homepage/channel/soundChannelV1/5/1.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21497&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "给宝宝冲奶粉,冲稀点不上火,浓点更营养?",
"bgUrl": "homepage/channel/soundChannelV1/5/2.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21506&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "怎样辨别奶粉中含有香精?",
"bgUrl": "homepage/channel/soundChannelV1/5/3.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21455&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "怎样判断宝宝吃饱了没?",
"bgUrl": "homepage/channel/soundChannelV1/5/4.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21495&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "奶粉颜色偏黄好?还是偏白好?",
"bgUrl": "homepage/channel/soundChannelV1/5/5.jpg"
},
{
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21489&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
},
"desc": "冲奶粉,不能用哪种水?",
"bgUrl": "homepage/channel/soundChannelV1/5/6.jpg"
}
]
],
"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": [
{
"btnTitle": "12类系列课程",
"subTitle": "育儿课程权益",
"level": "钻石会员",
"btnSubTitle": "立即了解",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
},
"bgUrl": "homepage/cardbg1.png"
},
{
"btnTitle": "",
"showCornerTxt": "",
"subTitle": "来自万年黑土的健康食品",
"level": "北纬47°系列",
"btnSubTitle": "",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/shopMainList/topicNew/index?id=1000265&entrySource=xmh_wechatmp_home_recgoods"
},
"bgUrl": "homepage/cardbg2.png"
},
{
"btnTitle": "",
"showCornerTxt": "",
"subTitle": "专家文章、育儿知识、饮食知识",
"level": "育儿宝典",
"btnSubTitle": "",
"link": {
"extra": {},
"type": 3,
"url": "https://mom.feihe.com/babyWikipedia/audioDetail?id=21489&type=3&period_id=5&tag_id=1&navActive=1&fnTagId=0"
"type": 1,
"url": "/pages/library/ContentLibrary"
},
"desc": "冲奶粉,不能用哪种水?",
"bgUrl": "homepage/channel/soundChannelV1/5/6.jpg"
}]
"bgUrl": "homepage/cardbg3.png"
}
],
"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": [{
"btnTitle": "12类系列课程",
"subTitle": "育儿课程权益",
"level": "钻石会员",
"btnSubTitle": "立即了解",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/xmhMainProcess/member/index?entrySource=xmh_wechatmp_points_recgoodsbot"
},
"bgUrl": "homepage/cardbg1.png"
}, {
"btnTitle": "",
"showCornerTxt": "",
"subTitle": "来自万年黑土的健康食品",
"level": "北纬47°系列",
"btnSubTitle": "",
"link": {
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "subPackages/shopMainList/topicNew/index?id=1000265&entrySource=xmh_wechatmp_home_recgoods"
"qrInfoList": [
{
"qrUrl": "homepage/qrcode_gzh.png",
"title": "公众号",
"desc": "长按关注<span style:'color:#D3A358;'>星妈会</span>公众号,了解更多专业育儿资讯"
},
"bgUrl": "homepage/cardbg2.png"
}, {
"btnTitle": "",
"showCornerTxt": "",
"subTitle": "专家文章、育儿知识、饮食知识",
"level": "育儿宝典",
"btnSubTitle": "",
"link": {
"extra": {},
"type": 1,
"url": "/pages/library/ContentLibrary"
{
"qrUrl": "homepage/qrcode_qw.png",
"title": "企业微信",
"desc": "长按添加<span style:'color:#D3A358;'>星妈管家</span>,享受专家问诊与社群福利活动"
},
"bgUrl": "homepage/cardbg3.png"
}],
"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>视频号,了解更多专业育儿资讯"
}],
{
"qrUrl": "homepage/qrcode_sph.png",
"title": "视频号",
"desc": "扫码关注<span style:'color:#D3A358;'>星妈会</span>视频号,了解更多专业育儿资讯"
}
],
"childrenInfoListMianTitle": "育儿智库",
"expertTeam": {
"maintitle": "专家团",
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -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" :
{
"navigationBarTitleText" : ""
"path": "pages/testPage/testPage",
"style": {
"navigationBarTitleText": ""
}
},
{
"path" : "pages/thirdJumpMiddlePage/thirdJumpMiddlePage",
"style" :
{
"navigationBarTitleText" : ""
"path": "pages/thirdJumpMiddlePage/thirdJumpMiddlePage",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "pages/XingmaLabDetailPage/XingmaLabDetailPage",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"enableShare": true,
"shareAppMessage": true,
"shareTimeline": false
}
},
{
"path": "pages/XingmaLabPublishPage/XingmaLabPublishPage",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}
],
......
# 星妈实验室详情页面 (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
- 添加交互动画和状态反馈
// 星妈实验室详情页面样式
.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;
}
}
<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>
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
}
# 星妈实验室发布页面更新日志
## 版本 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. 遵循项目开发规范
# 星妈实验室发布页面
## 功能概述
这是一个星妈实验室的藏品发布页面,支持用户上传藏品图片、编辑文案介绍,并进行发布。
## 主要功能
### 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
// 星妈实验室发布页面样式
.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;
}
}
<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>
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]
}
<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>
// 星妈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
<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
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;
},
},
});
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment