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 @@
取消
保存成员信息
+
+
+
+