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`
}
}
This diff is collapsed.
......@@ -313,6 +313,26 @@
],
"tool": [
[
{
"link": {
"extra": {},
"type": 1,
"url": "/pages/xingmaLab/xingmaLab"
},
"title": "星妈会Lab",
"desc": "星妈会Lab",
"bgUrl": "my/icon_xingma_lab1.png"
},
{
"link": {
"extra": {},
"type": 1,
"url": "/pages/naming/naming"
},
"title": "星妈起名",
"desc": "星妈起名",
"bgUrl": "my/naming.png"
},
{
"link": {
"extra": {},
......@@ -425,6 +445,15 @@
"脑发育"
],
"activeInfo": [
{
"img": "https://course.feihe.com/momclub-picture/my/vipAct090201.png",
"extra": {
"envVersion": "release",
"appId": "wx4205ec55b793245e"
},
"type": 2,
"url": "/subPackages/shopMainProcess/product/index?productId=739634042657637394&skuId=739635029460743612"
},
{
"img": "https://course.feihe.com/momclub-picture/my/activeImg0823.png",
"extra": {
......@@ -441,4 +470,4 @@
"母婴店"
]
}
}
\ No newline at end of file
}
\ No newline at end of file
......@@ -51,6 +51,12 @@
"navigationStyle": "custom"
}
},
{
"path": "pages/xingmaLab/xingmaLab",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/goodsDetail/goodsDetail",
"style": {
......@@ -163,17 +169,32 @@
}
},
{
"path" : "pages/testPage/testPage",
"style" :
"path": "pages/testPage/testPage",
"style": {
"navigationBarTitleText": ""
}
},
{
"navigationBarTitleText" : ""
"path": "pages/thirdJumpMiddlePage/thirdJumpMiddlePage",
"style": {
"navigationBarTitleText": ""
}
},
{
"path" : "pages/thirdJumpMiddlePage/thirdJumpMiddlePage",
"style" :
"path": "pages/XingmaLabDetailPage/XingmaLabDetailPage",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"enableShare": true,
"shareAppMessage": true,
"shareTimeline": false
}
},
{
"navigationBarTitleText" : ""
"path": "pages/XingmaLabPublishPage/XingmaLabPublishPage",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}
],
......
# 星妈实验室详情页面 (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;
}
}
This diff is collapsed.
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
This diff is collapsed.
This diff is collapsed.
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>
This diff is collapsed.
This diff is collapsed.
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;
},
},
});
This diff is collapsed.
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