From d520bc275aadbae3cecb33ee2edfee2523447a0b Mon Sep 17 00:00:00 2001 From: 17792275749 <812100002@qq.com> Date: Tue, 12 May 2026 10:33:02 +0800 Subject: [PATCH] =?UTF-8?q?[AI=20Generated]:=20feat(Views):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E8=AE=BE=E5=A4=87=E6=88=90=E5=91=98=E9=A1=B5=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E4=B8=8E=E6=A0=B7=E5=BC=8F=E5=8F=8A=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=88=90=E5=91=98=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- miniprogram/app.json | 2 + miniprogram/pages/addMember/addMember.json | 4 + miniprogram/pages/addMember/addMember.less | 221 ++++++++++++++++++ miniprogram/pages/addMember/addMember.ts | 161 +++++++++++++ miniprogram/pages/addMember/addMember.wxml | 112 +++++++++ .../equipmentMember/equipmentMember.json | 4 + .../equipmentMember/equipmentMember.less | 0 .../pages/equipmentMember/equipmentMember.ts | 135 +++++++++++ .../equipmentMember/equipmentMember.wxml | 15 ++ 9 files changed, 654 insertions(+) create mode 100644 miniprogram/pages/addMember/addMember.json create mode 100644 miniprogram/pages/addMember/addMember.less create mode 100644 miniprogram/pages/addMember/addMember.ts create mode 100644 miniprogram/pages/addMember/addMember.wxml create mode 100644 miniprogram/pages/equipmentMember/equipmentMember.json create mode 100644 miniprogram/pages/equipmentMember/equipmentMember.less create mode 100644 miniprogram/pages/equipmentMember/equipmentMember.ts create mode 100644 miniprogram/pages/equipmentMember/equipmentMember.wxml diff --git a/miniprogram/app.json b/miniprogram/app.json index f8e33e7..eddd953 100644 --- a/miniprogram/app.json +++ b/miniprogram/app.json @@ -1,9 +1,11 @@ { "pages": [ + "pages/equipmentMember/equipmentMember", "pages/login/login", "pages/connectedDevice/connectedDevice", "pages/connectedWifi/connectedWifi", "pages/supplementPersonal/supplementPersonal", + "pages/addMember/addMember", "pages/home/home", "pages/equipment/equipment", "pages/data/data", diff --git a/miniprogram/pages/addMember/addMember.json b/miniprogram/pages/addMember/addMember.json new file mode 100644 index 0000000..df62241 --- /dev/null +++ b/miniprogram/pages/addMember/addMember.json @@ -0,0 +1,4 @@ +{ + "navigationBarTitleText": "添加成员", + "usingComponents": {} +} diff --git a/miniprogram/pages/addMember/addMember.less b/miniprogram/pages/addMember/addMember.less new file mode 100644 index 0000000..88456a1 --- /dev/null +++ b/miniprogram/pages/addMember/addMember.less @@ -0,0 +1,221 @@ +.add-member { + width: 100%; + height: 100%; + display: flex; + flex-flow: column; + + /* 顶部浅蓝提示条 */ + .tips { + width: 100%; + height: 56rpx; + display: flex; + margin-bottom: 24rpx; + padding-left: 30rpx; + align-items: center; + box-sizing: border-box; + background-color: rgba(19, 133, 250, 0.2); + + .tips-icon { + color: #1385FA; + width: 28rpx; + height: 28rpx; + font-size: 20rpx; + font-weight: bold; + margin-right: 10rpx; + line-height: 24rpx; + text-align: center; + border-radius: 50%; + box-sizing: border-box; + border: 1rpx solid #1385FA; + } + + .tips-text { + color: #1385FA; + height: 24rpx; + font-size: 24rpx; + line-height: 24rpx; + } + } + + .form { + width: 100%; + flex: 1; + overflow: hidden; + padding: 0 30rpx; + margin-bottom: 40rpx; + box-sizing: border-box; + + /* 表单卡片 */ + .form-card { + width: 100%; + padding: 40rpx 30rpx; + border-radius: 16rpx; + box-sizing: border-box; + margin-bottom: 40rpx; + background-color: #FFFFFF; + + .form-row { + width: 100%; + margin-bottom: 40rpx; + + &:last-child { + margin-bottom: 0; + } + } + + .form-label { + width: 100%; + height: 40rpx; + display: flex; + flex-wrap: nowrap; + margin-bottom: 18rpx; + + .label-text { + color: #252535; + height: 40rpx; + font-size: 28rpx; + line-height: 40rpx; + font-weight: bold; + margin-right: 6rpx; + } + + .label-star { + color: #FF4D4F; + height: 40rpx; + font-weight: 500; + font-size: 28rpx; + line-height: 40rpx; + } + } + + .form-control { + width: 100%; + } + + /* 可输入区域 */ + .form-input { + width: 100%; + height: 88rpx; + padding: 0 30rpx; + color: #252535; + font-size: 26rpx; + border-radius: 16rpx; + box-sizing: border-box; + background-color: #FFFFFF; + border: 2rpx solid #E6E6EA; + } + + .form-placeholder { + color: #B6B6B6; + font-size: 26rpx; + } + + /* 输入框 + 后缀容器(身高 cm) */ + .form-input-wrap { + position: relative; + width: 630rpx; + + .form-input-with-suffix { + padding-right: 80rpx; + } + + .form-suffix-inside { + position: absolute; + right: 30rpx; + top: 0; + height: 88rpx; + color: #77849E; + font-size: 26rpx; + line-height: 88rpx; + } + } + + /* 只读区域(性别 / 年龄) */ + .form-readonly { + width: 630rpx; + height: 88rpx; + box-sizing: border-box; + padding: 0 24rpx; + background: #F6F6F6; + border-radius: 16rpx; + display: flex; + align-items: center; + + .readonly-text { + color: #252535; + font-size: 26rpx; + } + + .readonly-placeholder { + color: #B6B6B6; + font-size: 26rpx; + } + } + + .form-readonly-with-suffix { + justify-content: space-between; + + .form-suffix { + color: #77849E; + height: 88rpx; + font-size: 26rpx; + line-height: 88rpx; + } + } + } + + /* 从已有成员中选择(蓝色描边幽灵按钮) */ + .ghost-btn { + color: #1385FA; + width: 580rpx; + height: 88rpx; + font-size: 32rpx; + font-weight: bold; + text-align: center; + line-height: 84rpx; + border-radius: 44rpx; + box-sizing: border-box; + border: 2rpx solid #1385FA; + margin: 0 auto; + } + } + + /* 底部双按钮 */ + .actions { + width: 100%; + height: 120rpx; + padding: 0 55rpx; + display: flex; + flex-wrap: nowrap; + align-items: center; + justify-content: space-between; + box-sizing: border-box; + background-color: #FFFFFF; + box-shadow: 0 2rpx 8rpx 0 rgba(19, 133, 250, 0.06); + + .btn-cancel { + color: #1385FA; + width: 300rpx; + height: 88rpx; + font-size: 32rpx; + text-align: center; + line-height: 84rpx; + border-radius: 44rpx; + box-sizing: border-box; + border: 2rpx solid #1385FA; + background-color: #FFFFFF; + } + + .btn-primary { + color: #FFFFFF; + width: 300rpx; + height: 88rpx; + font-size: 32rpx; + font-weight: bold; + text-align: center; + line-height: 88rpx; + border-radius: 44rpx; + background-color: #1385FA; + } + } +} diff --git a/miniprogram/pages/addMember/addMember.ts b/miniprogram/pages/addMember/addMember.ts new file mode 100644 index 0000000..66264a3 --- /dev/null +++ b/miniprogram/pages/addMember/addMember.ts @@ -0,0 +1,161 @@ +/** 表单数据模型 */ +interface MemberForm { + /** 姓名 */ + name: string + /** 身份证号 */ + idCard: string + /** 性别(由身份证解析,只读) */ + gender: string + /** 年龄(由身份证解析,只读) */ + age: string + /** 身高(cm) */ + height: string +} + +/** 身份证解析结果 */ +interface IdCardParsed { + /** 性别,空字符串表示解析失败 */ + gender: string + /** 年龄,空字符串表示解析失败 */ + age: string +} + +/** + * 添加成员页 + * 收集姓名、身份证号、身高,并根据身份证自动解析性别与年龄 + * 保存后返回设备成员列表页 + */ +Page({ + data: { + // 表单数据 + form: { + name: '', // 姓名 + idCard: '', // 身份证号 + gender: '', // 性别(由身份证解析,只读) + age: '', // 年龄(由身份证解析,只读) + height: '' // 身高(cm) + } as MemberForm + }, + + /** + * 姓名输入 + */ + onNameInput(e: WechatMiniprogram.Input) { + this.setData({ + 'form.name': e.detail.value + }) + }, + + /** + * 身份证号输入 + * 长度满 18 位时自动解析性别与年龄,否则清空 + */ + onIdCardInput(e: WechatMiniprogram.Input) { + const idCard = (e.detail.value || '').trim().toUpperCase() + const parsed = this.parseIdCard(idCard) + + this.setData({ + 'form.idCard': idCard, + 'form.gender': parsed.gender, + 'form.age': parsed.age + }) + }, + + /** + * 身高输入 + */ + onHeightInput(e: WechatMiniprogram.Input) { + this.setData({ + 'form.height': e.detail.value + }) + }, + + /** + * 解析身份证号,返回性别与年龄 + * @param idCard 18 位身份证号 + */ + parseIdCard(idCard: string): IdCardParsed { + // 简单校验:18 位且前 17 位为数字 + const reg = /^\d{17}[\dX]$/ + if (!reg.test(idCard)) { + return { gender: '', age: '' } + } + + // 性别:第 17 位奇数为男,偶数为女 + const genderCode = parseInt(idCard.charAt(16), 10) + const gender = genderCode % 2 === 1 ? '男' : '女' + + // 出生日期:第 7-14 位 + const year = parseInt(idCard.substr(6, 4), 10) + const month = parseInt(idCard.substr(10, 2), 10) + const day = parseInt(idCard.substr(12, 2), 10) + + // 基本合法性校验 + if ( + !year || !month || !day || + month < 1 || month > 12 || + day < 1 || day > 31 + ) { + return { gender: '', age: '' } + } + + // 计算周岁(看是否过了今年生日) + const now = new Date() + let age = now.getFullYear() - year + const nowMonth = now.getMonth() + 1 + const nowDay = now.getDate() + if (nowMonth < month || (nowMonth === month && nowDay < day)) { + age -= 1 + } + + if (age < 0 || age > 150) { + return { gender: '', age: '' } + } + + return { gender, age: String(age) } + }, + + /** + * 从已有成员中选择(暂留空,后续接入选择浮层) + */ + onTapSelectExisting() { + // TODO: 接入"从已有成员中选择"浮层/选择页 + }, + + /** + * 取消:直接返回上一页 + */ + onCancel() { + wx.navigateBack() + }, + + /** + * 保存成员信息 + * 必填:姓名、身份证号(18 位且解析成功)、身高 + * 未通过时 toast 提示,通过后返回上一页 + */ + onSubmit() { + const { name, idCard, gender, age, height } = this.data.form + const heightNum = parseFloat(height) + + if (!name.trim()) { + wx.showToast({ title: '请填写姓名', icon: 'none' }) + return + } + if (idCard.length !== 18) { + wx.showToast({ title: '请填写正确的身份证号', icon: 'none' }) + return + } + if (!gender || !age) { + wx.showToast({ title: '身份证号有误,请检查', icon: 'none' }) + return + } + if (!height || isNaN(heightNum) || heightNum <= 0) { + wx.showToast({ title: '请填写身高', icon: 'none' }) + return + } + + // TODO: 此处后续接入成员保存接口 + wx.navigateBack() + } +}) diff --git a/miniprogram/pages/addMember/addMember.wxml b/miniprogram/pages/addMember/addMember.wxml new file mode 100644 index 0000000..9131b21 --- /dev/null +++ b/miniprogram/pages/addMember/addMember.wxml @@ -0,0 +1,112 @@ + + + + + ! + 最多支持 10 位成员 + + + + + + + + + + 姓名 + * + + + + + + + + + + 身份证号 + * + + + + + + + + + + 性别 + + + + + {{ form.gender }} + + + 自动生成,无需填写 + + + + + + + + + 年龄 + + + + + {{ form.age }} + + + 自动生成,无需填写 + + + + + + + + + + 身高 + * + + + + + cm + + + + + + + 从已有成员中选择 + + + + + 取消 + 保存成员信息 + + diff --git a/miniprogram/pages/equipmentMember/equipmentMember.json b/miniprogram/pages/equipmentMember/equipmentMember.json new file mode 100644 index 0000000..0e7835c --- /dev/null +++ b/miniprogram/pages/equipmentMember/equipmentMember.json @@ -0,0 +1,4 @@ +{ + "navigationBarTitleText": "设备成员", + "usingComponents": {} +} diff --git a/miniprogram/pages/equipmentMember/equipmentMember.less b/miniprogram/pages/equipmentMember/equipmentMember.less new file mode 100644 index 0000000..e69de29 diff --git a/miniprogram/pages/equipmentMember/equipmentMember.ts b/miniprogram/pages/equipmentMember/equipmentMember.ts new file mode 100644 index 0000000..8306ea1 --- /dev/null +++ b/miniprogram/pages/equipmentMember/equipmentMember.ts @@ -0,0 +1,135 @@ +/** 成员项 */ +interface MemberItem { + /** 唯一 ID */ + id: string + /** 姓名 */ + name: string + /** 性别 */ + gender: '男' | '女' + /** 年龄 */ + age: number + /** 身高(cm) */ + height: number + /** 头像色块(无图片时使用) */ + avatar: string + /** 是否本人 */ + isSelf: boolean + /** 是否他人添加(只读,不显示编辑/删除) */ + isFromOther: boolean +} + +/** 设备卡片 */ +interface DeviceCard { + /** 设备 ID */ + id: string + /** 设备名称 */ + name: string + /** 已使用容量(成员数) */ + capacityUsed: number + /** 总容量 */ + capacityTotal: number +} + +/** + * 设备成员页 + * 两态:已连接(connected=true) / 未连接(connected=false) + * connected 为页面内部全局状态,后续接入真实设备状态时替换 + */ +Page({ + data: { + // 设备连接状态(全局,内部控制) + connected: true, + + // 设备卡片 + deviceCard: { + id: 'device-001', + name: 'MX-W30A1', + capacityUsed: 4, + capacityTotal: 10 + } as DeviceCard, + + // 成员列表(色块占位头像) + memberList: [ + { + id: 'm-001', + name: '陈小飞', + gender: '男', + age: 28, + height: 175, + avatar: '#1385FA', + isSelf: true, + isFromOther: false + }, + { + id: 'm-002', + name: '李镇南', + gender: '男', + age: 32, + height: 178, + avatar: '#2AC79F', + isSelf: false, + isFromOther: false + }, + { + id: 'm-003', + name: '张颖', + gender: '女', + age: 26, + height: 165, + avatar: '#FF8FAB', + isSelf: false, + isFromOther: false + }, + { + id: 'm-004', + name: '李镇南', + gender: '男', + age: 60, + height: 170, + avatar: '#FFB347', + isSelf: false, + isFromOther: true + } + ] as MemberItem[] + }, + + /** + * 编辑成员 + */ + onTapEdit(e: WechatMiniprogram.TouchEvent) { + const id = e.currentTarget.dataset.id as string + // TODO: 后续接入编辑成员浮层/页面 + wx.showToast({ title: `编辑 ${id}`, icon: 'none' }) + }, + + /** + * 删除成员 + */ + onTapDelete(e: WechatMiniprogram.TouchEvent) { + const id = e.currentTarget.dataset.id as string + wx.showModal({ + title: '提示', + content: '确定删除该成员?', + success: (res) => { + if (!res.confirm) return + // TODO: 后续接入删除成员接口 + const list = this.data.memberList.filter(m => m.id !== id) + this.setData({ + memberList: list, + 'deviceCard.capacityUsed': list.length + }) + } + }) + }, + + /** + * 添加成员:跳转到 addMember 页 + * 未连接态禁用 + */ + onTapAddMember() { + if (!this.data.connected) return + wx.navigateTo({ + url: '/pages/addMember/addMember' + }) + } +}) diff --git a/miniprogram/pages/equipmentMember/equipmentMember.wxml b/miniprogram/pages/equipmentMember/equipmentMember.wxml new file mode 100644 index 0000000..7d5a18c --- /dev/null +++ b/miniprogram/pages/equipmentMember/equipmentMember.wxml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + 添加成员(最多10位) + + \ No newline at end of file