diff --git a/.idea/claudeCodeTabState.xml b/.idea/claudeCodeTabState.xml deleted file mode 100644 index ba4c915..0000000 --- a/.idea/claudeCodeTabState.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/miniprogram/app.json b/miniprogram/app.json index 3c5f1a2..db068c6 100644 --- a/miniprogram/app.json +++ b/miniprogram/app.json @@ -1,14 +1,14 @@ { "pages": [ - "pages/measurementReport/measurementReport", + "pages/addMember/addMember", "pages/home/home", "pages/login/login", "pages/connectedDevice/connectedDevice", "pages/connectedWifi/connectedWifi", "pages/supplementPersonal/supplementPersonal", "pages/equipmentMember/equipmentMember", - "pages/addMember/addMember", "pages/equipment/equipment", + "pages/measurementReport/measurementReport", "pages/data/data", "pages/my/my" ], diff --git a/miniprogram/components/selectMemberDrawer/selectMemberDrawer.json b/miniprogram/components/selectMemberDrawer/selectMemberDrawer.json new file mode 100644 index 0000000..a89ef4d --- /dev/null +++ b/miniprogram/components/selectMemberDrawer/selectMemberDrawer.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} diff --git a/miniprogram/components/selectMemberDrawer/selectMemberDrawer.less b/miniprogram/components/selectMemberDrawer/selectMemberDrawer.less new file mode 100644 index 0000000..47242ce --- /dev/null +++ b/miniprogram/components/selectMemberDrawer/selectMemberDrawer.less @@ -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; +} diff --git a/miniprogram/components/selectMemberDrawer/selectMemberDrawer.ts b/miniprogram/components/selectMemberDrawer/selectMemberDrawer.ts new file mode 100644 index 0000000..1d3c6af --- /dev/null +++ b/miniprogram/components/selectMemberDrawer/selectMemberDrawer.ts @@ -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) + } + } +}) diff --git a/miniprogram/components/selectMemberDrawer/selectMemberDrawer.wxml b/miniprogram/components/selectMemberDrawer/selectMemberDrawer.wxml new file mode 100644 index 0000000..de2307d --- /dev/null +++ b/miniprogram/components/selectMemberDrawer/selectMemberDrawer.wxml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + 选择已有成员 + + + + + + + + + + + + + + + + + + + + + + + {{ item.name }} + {{ item.gender }}·{{ item.age }}岁 + + + + + + + {{ item.height }}cm + + + + + + + + diff --git a/miniprogram/pages/addMember/addMember.json b/miniprogram/pages/addMember/addMember.json index df62241..a5b5e26 100644 --- a/miniprogram/pages/addMember/addMember.json +++ b/miniprogram/pages/addMember/addMember.json @@ -1,4 +1,6 @@ { "navigationBarTitleText": "添加成员", - "usingComponents": {} + "usingComponents": { + "select-member-drawer": "/components/selectMemberDrawer/selectMemberDrawer" + } } diff --git a/miniprogram/pages/addMember/addMember.ts b/miniprogram/pages/addMember/addMember.ts index 66264a3..7de9830 100644 --- a/miniprogram/pages/addMember/addMember.ts +++ b/miniprogram/pages/addMember/addMember.ts @@ -20,6 +20,24 @@ interface IdCardParsed { 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: { // 表单数据 form: { - name: '', // 姓名 - idCard: '', // 身份证号 - gender: '', // 性别(由身份证解析,只读) - age: '', // 年龄(由身份证解析,只读) - height: '' // 身高(cm) - } as MemberForm + name: '', + idCard: '', + gender: '', + age: '', + height: '' + } 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() { - // TODO: 接入"从已有成员中选择"浮层/选择页 + this.setData({ showSelectDrawer: true }) + }, + + /** 关闭选择成员抽屉 */ + onSelectMemberClose() { + this.setData({ showSelectDrawer: false }) + }, + + /** + * 选中成员后填充表单 + * @param e 携带 detail(SelectMemberItem) 的自定义事件 + */ + onSelectMember(e: WechatMiniprogram.CustomEvent) { + 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) + }) }, /** diff --git a/miniprogram/pages/addMember/addMember.wxml b/miniprogram/pages/addMember/addMember.wxml index 9131b21..85fb454 100644 --- a/miniprogram/pages/addMember/addMember.wxml +++ b/miniprogram/pages/addMember/addMember.wxml @@ -109,4 +109,12 @@ 取消 保存成员信息 + + + +