[AI Generated]: feat(Comp): 新增选择已有成员抽屉组件并接入 addMember 页面
This commit is contained in:
Generated
-6
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ClaudeCodeTabState">
|
|
||||||
<option name="tabCount" value="2" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"pages": [
|
"pages": [
|
||||||
"pages/measurementReport/measurementReport",
|
"pages/addMember/addMember",
|
||||||
"pages/home/home",
|
"pages/home/home",
|
||||||
"pages/login/login",
|
"pages/login/login",
|
||||||
"pages/connectedDevice/connectedDevice",
|
"pages/connectedDevice/connectedDevice",
|
||||||
"pages/connectedWifi/connectedWifi",
|
"pages/connectedWifi/connectedWifi",
|
||||||
"pages/supplementPersonal/supplementPersonal",
|
"pages/supplementPersonal/supplementPersonal",
|
||||||
"pages/equipmentMember/equipmentMember",
|
"pages/equipmentMember/equipmentMember",
|
||||||
"pages/addMember/addMember",
|
|
||||||
"pages/equipment/equipment",
|
"pages/equipment/equipment",
|
||||||
|
"pages/measurementReport/measurementReport",
|
||||||
"pages/data/data",
|
"pages/data/data",
|
||||||
"pages/my/my"
|
"pages/my/my"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"component": true,
|
||||||
|
"usingComponents": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
/* 遮罩层 */
|
||||||
|
.drawer-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(37, 37, 53, 0.6);
|
||||||
|
z-index: 100;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
|
||||||
|
&--visible {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 抽屉面板 */
|
||||||
|
.drawer-panel {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
/* 最大高度约 75% 屏幕 */
|
||||||
|
height: 85vh;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
border-radius: 24rpx 24rpx 0 0;
|
||||||
|
z-index: 101;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
transform: translateY(100%);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
|
||||||
|
&--visible {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 拖拽把手 */
|
||||||
|
.drawer-handle {
|
||||||
|
width: 72rpx;
|
||||||
|
height: 6rpx;
|
||||||
|
background-color: #77849E;
|
||||||
|
border-radius: 3rpx;
|
||||||
|
margin: 32rpx auto 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 标题栏 */
|
||||||
|
.drawer-header {
|
||||||
|
width: 100%;
|
||||||
|
height: 32rpx;
|
||||||
|
padding: 0 30rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.drawer-title {
|
||||||
|
color: #252535;
|
||||||
|
height: 32rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 关闭按钮 */
|
||||||
|
.drawer-close {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.drawer-close-icon {
|
||||||
|
width: 28rpx;
|
||||||
|
height: 28rpx;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 100%;
|
||||||
|
height: 3rpx;
|
||||||
|
background-color: #252535;
|
||||||
|
border-radius: 2rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
transform: translate(-50%, -50%) rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
transform: translate(-50%, -50%) rotate(-45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 顶部分隔线 */
|
||||||
|
.drawer-divider {
|
||||||
|
width: 690rpx;
|
||||||
|
height: 2rpx;
|
||||||
|
background-color: #EAEDF1;
|
||||||
|
margin: 39rpx 30rpx 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 成员滚动列表 */
|
||||||
|
.drawer-list {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 成员行 */
|
||||||
|
.member-item {
|
||||||
|
width: 100%;
|
||||||
|
height: 90rpx;
|
||||||
|
padding: 0 30rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 24rpx;
|
||||||
|
|
||||||
|
/* 有图片头像 */
|
||||||
|
.member-avatar {
|
||||||
|
width: 90rpx;
|
||||||
|
height: 90rpx;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&--selected {
|
||||||
|
border: 3rpx solid #50A6FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 纯色占位头像 */
|
||||||
|
.member-avatar-placeholder {
|
||||||
|
width: 90rpx;
|
||||||
|
height: 90rpx;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
/* 男:蓝色 */
|
||||||
|
&--male {
|
||||||
|
background-color: #C6E6FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 女:粉色 */
|
||||||
|
&--female {
|
||||||
|
background-color: #FFD5E3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选中男 */
|
||||||
|
&--selected-male {
|
||||||
|
border: 3rpx solid #50A6FF;
|
||||||
|
width: 96rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
margin: -3rpx 0 0 -3rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选中女 */
|
||||||
|
&--selected-female {
|
||||||
|
border: 3rpx solid #FF8FB5;
|
||||||
|
width: 96rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
margin: -3rpx 0 0 -3rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 姓名 + 副标题 */
|
||||||
|
.member-info {
|
||||||
|
flex: 1;
|
||||||
|
height: 78rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-left: 23rpx;
|
||||||
|
|
||||||
|
.member-name {
|
||||||
|
color: #333333;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 32rpx;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-sub {
|
||||||
|
color: #77849E;
|
||||||
|
font-size: 26rpx;
|
||||||
|
line-height: 34rpx;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 竖向分隔线 */
|
||||||
|
.member-divider {
|
||||||
|
width: 2rpx;
|
||||||
|
height: 24rpx;
|
||||||
|
background-color: #EAEDF1;
|
||||||
|
border-radius: 1rpx;
|
||||||
|
margin-left: 17rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 身高 */
|
||||||
|
.member-height {
|
||||||
|
color: #77849E;
|
||||||
|
font-size: 26rpx;
|
||||||
|
line-height: 34rpx;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-left: 19rpx;
|
||||||
|
width: 76rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 行间水平分隔线 */
|
||||||
|
.member-separator {
|
||||||
|
width: 690rpx;
|
||||||
|
height: 2rpx;
|
||||||
|
background-color: #EAEDF1;
|
||||||
|
margin: 24rpx 30rpx 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/** 成员数据项 */
|
||||||
|
interface SelectMemberItem {
|
||||||
|
/** 唯一标识 */
|
||||||
|
id: string
|
||||||
|
/** 姓名 */
|
||||||
|
name: string
|
||||||
|
/** 性别 */
|
||||||
|
gender: '男' | '女'
|
||||||
|
/** 年龄 */
|
||||||
|
age: number
|
||||||
|
/** 身高(cm) */
|
||||||
|
height: number
|
||||||
|
/** 头像 URL,无则显示彩色占位圆 */
|
||||||
|
avatar?: string
|
||||||
|
/** 是否已选中 */
|
||||||
|
selected?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择已有成员抽屉组件
|
||||||
|
* Properties: show(控制显示), members(成员列表)
|
||||||
|
* Events: close(关闭), select(选中成员,携带 SelectMemberItem)
|
||||||
|
*/
|
||||||
|
Component({
|
||||||
|
properties: {
|
||||||
|
/** 是否显示抽屉 */
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
/** 成员列表 */
|
||||||
|
members: {
|
||||||
|
type: Array,
|
||||||
|
value: [] as SelectMemberItem[]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data: {
|
||||||
|
/** 控制 wx:if,DOM 是否存在 */
|
||||||
|
innerShow: false,
|
||||||
|
/** 控制 --visible 类,触发 CSS transition */
|
||||||
|
animVisible: false
|
||||||
|
},
|
||||||
|
|
||||||
|
observers: {
|
||||||
|
/**
|
||||||
|
* 监听外部 show 变化,错开两帧:
|
||||||
|
* 打开:先插入 DOM,下一帧加动画类
|
||||||
|
* 关闭:先移除动画类,等 transition 结束再移除 DOM
|
||||||
|
*/
|
||||||
|
show(val: boolean) {
|
||||||
|
if (val) {
|
||||||
|
this.setData({ innerShow: true })
|
||||||
|
// 延迟一帧,让 DOM 先以初始状态渲染,再触发 transition
|
||||||
|
setTimeout(() => {
|
||||||
|
this.setData({ animVisible: true })
|
||||||
|
}, 20)
|
||||||
|
} else {
|
||||||
|
this.setData({ animVisible: false })
|
||||||
|
// 等 CSS transition 结束(0.3s)再移除 DOM
|
||||||
|
setTimeout(() => {
|
||||||
|
this.setData({ innerShow: false })
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
/** 点击遮罩关闭 */
|
||||||
|
onTapMask() {
|
||||||
|
this.triggerEvent('close')
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 点击关闭按钮 */
|
||||||
|
onTapClose() {
|
||||||
|
this.triggerEvent('close')
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点击成员行,触发 select 事件
|
||||||
|
* @param e 携带 data-member 的点击事件
|
||||||
|
*/
|
||||||
|
onTapMember(e: WechatMiniprogram.TouchEvent) {
|
||||||
|
const member = e.currentTarget.dataset.member as SelectMemberItem
|
||||||
|
this.triggerEvent('select', member)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<!-- 选择已有成员抽屉 -->
|
||||||
|
<block wx:if="{{ innerShow }}">
|
||||||
|
<!-- 遮罩 -->
|
||||||
|
<view class="drawer-mask {{ animVisible ? 'drawer-mask--visible' : '' }}" bind:tap="onTapMask"></view>
|
||||||
|
|
||||||
|
<!-- 抽屉面板 -->
|
||||||
|
<view class="drawer-panel {{ animVisible ? 'drawer-panel--visible' : '' }}">
|
||||||
|
|
||||||
|
<!-- 顶部拖拽把手 -->
|
||||||
|
<view class="drawer-handle"></view>
|
||||||
|
|
||||||
|
<!-- 标题栏 -->
|
||||||
|
<view class="drawer-header">
|
||||||
|
<text class="drawer-title">选择已有成员</text>
|
||||||
|
<view class="drawer-close" bind:tap="onTapClose">
|
||||||
|
<view class="drawer-close-icon"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 分隔线 -->
|
||||||
|
<view class="drawer-divider"></view>
|
||||||
|
|
||||||
|
<!-- 成员列表 -->
|
||||||
|
<scroll-view class="drawer-list" scroll-y>
|
||||||
|
<block wx:for="{{ members }}" wx:key="id">
|
||||||
|
<view class="member-item" bind:tap="onTapMember" data-member="{{ item }}">
|
||||||
|
<!-- 头像 -->
|
||||||
|
<block wx:if="{{ item.avatar }}">
|
||||||
|
<image class="member-avatar {{ item.selected ? 'member-avatar--selected' : '' }}" src="{{ item.avatar }}" mode="aspectFill"></image>
|
||||||
|
</block>
|
||||||
|
<block wx:else>
|
||||||
|
<view class="member-avatar-placeholder {{ item.gender === '女' ? 'member-avatar-placeholder--female' : 'member-avatar-placeholder--male' }} {{ item.selected ? 'member-avatar-placeholder--selected-male' : '' }} {{ item.selected && item.gender === '女' ? 'member-avatar-placeholder--selected-female' : '' }}"></view>
|
||||||
|
</block>
|
||||||
|
|
||||||
|
<!-- 姓名 + 性别·年龄 -->
|
||||||
|
<view class="member-info">
|
||||||
|
<text class="member-name">{{ item.name }}</text>
|
||||||
|
<text class="member-sub">{{ item.gender }}·{{ item.age }}岁</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 竖向分隔线 -->
|
||||||
|
<view class="member-divider"></view>
|
||||||
|
|
||||||
|
<!-- 身高 -->
|
||||||
|
<text class="member-height">{{ item.height }}cm</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 水平分隔线 -->
|
||||||
|
<view class="member-separator"></view>
|
||||||
|
</block>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
{
|
{
|
||||||
"navigationBarTitleText": "添加成员",
|
"navigationBarTitleText": "添加成员",
|
||||||
"usingComponents": {}
|
"usingComponents": {
|
||||||
|
"select-member-drawer": "/components/selectMemberDrawer/selectMemberDrawer"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,24 @@ interface IdCardParsed {
|
|||||||
age: string
|
age: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 已有成员数据项 */
|
||||||
|
interface SelectMemberItem {
|
||||||
|
/** 唯一标识 */
|
||||||
|
id: string
|
||||||
|
/** 姓名 */
|
||||||
|
name: string
|
||||||
|
/** 性别 */
|
||||||
|
gender: '男' | '女'
|
||||||
|
/** 年龄 */
|
||||||
|
age: number
|
||||||
|
/** 身高(cm) */
|
||||||
|
height: number
|
||||||
|
/** 头像 URL,无则显示彩色占位圆 */
|
||||||
|
avatar?: string
|
||||||
|
/** 是否已选中 */
|
||||||
|
selected?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加成员页
|
* 添加成员页
|
||||||
* 收集姓名、身份证号、身高,并根据身份证自动解析性别与年龄
|
* 收集姓名、身份证号、身高,并根据身份证自动解析性别与年龄
|
||||||
@@ -29,12 +47,24 @@ Page({
|
|||||||
data: {
|
data: {
|
||||||
// 表单数据
|
// 表单数据
|
||||||
form: {
|
form: {
|
||||||
name: '', // 姓名
|
name: '',
|
||||||
idCard: '', // 身份证号
|
idCard: '',
|
||||||
gender: '', // 性别(由身份证解析,只读)
|
gender: '',
|
||||||
age: '', // 年龄(由身份证解析,只读)
|
age: '',
|
||||||
height: '' // 身高(cm)
|
height: ''
|
||||||
} as MemberForm
|
} as MemberForm,
|
||||||
|
|
||||||
|
// 抽屉显示状态
|
||||||
|
showSelectDrawer: false,
|
||||||
|
|
||||||
|
// TODO: 后续替换为接口数据
|
||||||
|
existingMembers: [
|
||||||
|
{ id: '1', name: '陈小飞', gender: '男', age: 32, height: 172, avatar: '' },
|
||||||
|
{ id: '2', name: '李镇南', gender: '男', age: 35, height: 185, avatar: '' },
|
||||||
|
{ id: '3', name: '张颖', gender: '女', age: 35, height: 185, avatar: '' },
|
||||||
|
{ id: '4', name: '李镇南', gender: '男', age: 35, height: 185, avatar: '' },
|
||||||
|
{ id: '5', name: '赵雪', gender: '女', age: 31, height: 165, avatar: '' }
|
||||||
|
] as SelectMemberItem[]
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,10 +146,30 @@ Page({
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从已有成员中选择(暂留空,后续接入选择浮层)
|
* 从已有成员中选择 — 打开抽屉
|
||||||
*/
|
*/
|
||||||
onTapSelectExisting() {
|
onTapSelectExisting() {
|
||||||
// TODO: 接入"从已有成员中选择"浮层/选择页
|
this.setData({ showSelectDrawer: true })
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 关闭选择成员抽屉 */
|
||||||
|
onSelectMemberClose() {
|
||||||
|
this.setData({ showSelectDrawer: false })
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选中成员后填充表单
|
||||||
|
* @param e 携带 detail(SelectMemberItem) 的自定义事件
|
||||||
|
*/
|
||||||
|
onSelectMember(e: WechatMiniprogram.CustomEvent<SelectMemberItem>) {
|
||||||
|
const { name, gender, age, height } = e.detail
|
||||||
|
this.setData({
|
||||||
|
showSelectDrawer: false,
|
||||||
|
'form.name': name,
|
||||||
|
'form.gender': gender,
|
||||||
|
'form.age': String(age),
|
||||||
|
'form.height': String(height)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -109,4 +109,12 @@
|
|||||||
<view class="btn-cancel" bind:tap="onCancel">取消</view>
|
<view class="btn-cancel" bind:tap="onCancel">取消</view>
|
||||||
<view class="btn-primary" bind:tap="onSubmit">保存成员信息</view>
|
<view class="btn-primary" bind:tap="onSubmit">保存成员信息</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 选择已有成员抽屉 -->
|
||||||
|
<select-member-drawer
|
||||||
|
show="{{ showSelectDrawer }}"
|
||||||
|
members="{{ existingMembers }}"
|
||||||
|
bind:close="onSelectMemberClose"
|
||||||
|
bind:select="onSelectMember">
|
||||||
|
</select-member-drawer>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
Reference in New Issue
Block a user