diff --git a/components/plate-input/plate-input.js b/components/plate-input/plate-input.js
new file mode 100644
index 0000000..4a8a01e
--- /dev/null
+++ b/components/plate-input/plate-input.js
@@ -0,0 +1,134 @@
+// plate-input.js
+// 车牌号输入组件:先选省份简称 → 再选城市代码 → 最后键盘输入号码
+Component({
+ properties: {
+ value: { type: String, value: '' }
+ },
+
+ data: {
+ plateChars: [],
+ numValue: '',
+ inputFocus: false,
+ showProvince: false,
+ showCity: false,
+ hasValue: false,
+ provinces: [
+ '京', '津', '沪', '渝', '冀', '豫', '云', '辽', '黑', '湘',
+ '皖', '鲁', '新', '苏', '浙', '赣', '鄂', '桂', '甘', '晋',
+ '蒙', '陕', '吉', '闽', '贵', '粤', '川', '青', '藏', '琼', '宁'
+ ],
+ cityLetters: [
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'J', 'K', 'L', 'M', 'N', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z'
+ ],
+ numSlots: [0, 1, 2, 3, 4, 5]
+ },
+
+ observers: {
+ 'value': function (val) {
+ if (val && val !== this._lastEmitted) {
+ this._parseValue(val)
+ }
+ }
+ },
+
+ lifetimes: {
+ attached() {
+ if (this.data.value) {
+ this._parseValue(this.data.value)
+ }
+ }
+ },
+
+ methods: {
+ _parseValue(val) {
+ const chars = val.split('')
+ const numValue = chars.slice(2).join('')
+ this.setData({
+ plateChars: chars,
+ numValue: numValue,
+ hasValue: chars.length > 0
+ })
+ },
+
+ _emit(chars) {
+ const value = chars.filter(Boolean).join('')
+ this._lastEmitted = value
+ this.triggerEvent('change', { value })
+ },
+
+ // 点击省份格
+ onProvinceTap() {
+ this.setData({ showProvince: true, showCity: false, inputFocus: false })
+ },
+
+ // 选择省份
+ selectProvince(e) {
+ const code = e.currentTarget.dataset.value
+ const chars = [code, this.data.plateChars[1]].filter(Boolean)
+ this.setData({ plateChars: chars, showProvince: false, showCity: true, hasValue: true })
+ this._emit(chars)
+ },
+
+ // 点击城市格
+ onCityTap() {
+ if (!this.data.plateChars[0]) {
+ this.setData({ showProvince: true })
+ return
+ }
+ this.setData({ showCity: true, showProvince: false, inputFocus: false })
+ },
+
+ // 选择城市代码
+ selectCity(e) {
+ const letter = e.currentTarget.dataset.value
+ const numPart = this.data.plateChars.slice(2).join('')
+ const chars = [this.data.plateChars[0], letter].concat(numPart.split(''))
+ this.setData({
+ plateChars: chars,
+ showCity: false,
+ numValue: numPart,
+ inputFocus: true,
+ hasValue: true
+ })
+ this._emit(chars)
+ },
+
+ // 点击号码格 → 弹出键盘
+ onNumTap() {
+ if (!this.data.plateChars[0] || !this.data.plateChars[1]) {
+ this.setData({ showProvince: true })
+ return
+ }
+ this.setData({ inputFocus: true, showProvince: false, showCity: false })
+ },
+
+ // 键盘输入号码
+ onNumInput(e) {
+ const raw = e.detail.value.toUpperCase().replace(/[^A-Z0-9]/g, '').slice(0, 6)
+ const chars = [this.data.plateChars[0], this.data.plateChars[1]].concat(raw.split(''))
+ this.setData({ plateChars: chars, numValue: raw, hasValue: true })
+ this._emit(chars)
+ },
+
+ // 关闭弹窗
+ hidePicker() {
+ this.setData({ showProvince: false, showCity: false })
+ },
+
+ noop() {},
+
+ // 清除车牌号
+ clearPlate() {
+ this.setData({
+ plateChars: [],
+ numValue: '',
+ inputFocus: false,
+ hasValue: false
+ })
+ this._emit([])
+ }
+ }
+})
diff --git a/components/plate-input/plate-input.json b/components/plate-input/plate-input.json
new file mode 100644
index 0000000..467ce29
--- /dev/null
+++ b/components/plate-input/plate-input.json
@@ -0,0 +1,3 @@
+{
+ "component": true
+}
diff --git a/components/plate-input/plate-input.wxml b/components/plate-input/plate-input.wxml
new file mode 100644
index 0000000..966f6ef
--- /dev/null
+++ b/components/plate-input/plate-input.wxml
@@ -0,0 +1,69 @@
+
+
+
+
+
+ {{plateChars[0] || '省'}}
+
+
+ {{plateChars[1] || '市'}}
+
+ ·
+
+
+
+
+
+
+
+ 清除
+
+
+
+
+
+
+
diff --git a/components/plate-input/plate-input.wxss b/components/plate-input/plate-input.wxss
new file mode 100644
index 0000000..49a92a1
--- /dev/null
+++ b/components/plate-input/plate-input.wxss
@@ -0,0 +1,155 @@
+/* plate-input.wxss */
+
+.plate-container {
+ flex: 1;
+ position: relative;
+ display: flex;
+ align-items: center;
+}
+
+/* 车牌格子区域 */
+.plate-body {
+ display: flex;
+ align-items: center;
+ background: #f5f7fa;
+ border: 2rpx solid #dce3ec;
+ border-radius: 12rpx;
+ padding: 8rpx 16rpx;
+ height: 72rpx;
+ flex: 1;
+}
+
+.plate-cell {
+ width: 56rpx;
+ height: 56rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 30rpx;
+ border-radius: 8rpx;
+ margin: 0 4rpx;
+ flex-shrink: 0;
+ transition: all 0.2s;
+}
+
+.plate-cell.empty {
+ color: #b8c9db;
+ background: #eaf0f7;
+ font-size: 24rpx;
+}
+
+.plate-cell.filled {
+ color: #2c3e50;
+ background: #ffffff;
+ border: 1rpx solid #dce3ec;
+ font-weight: 600;
+}
+
+.plate-cell.num {
+ width: 44rpx;
+}
+
+.plate-cell.num.extra {
+ border-style: dashed;
+ border-color: #c8d6e5;
+}
+
+.plate-sep {
+ font-size: 32rpx;
+ color: #b8c9db;
+ margin: 0 6rpx;
+ font-weight: bold;
+}
+
+/* 隐藏输入框(用于唤起键盘) */
+.plate-hidden-input {
+ position: absolute;
+ left: -9999rpx;
+ width: 0;
+ height: 0;
+ opacity: 0;
+}
+
+/* 清除按钮 */
+.plate-clear {
+ position: absolute;
+ right: -60rpx;
+ top: 50%;
+ transform: translateY(-50%);
+ font-size: 24rpx;
+ color: #ff4d4f;
+ padding: 8rpx 12rpx;
+ flex-shrink: 0;
+}
+
+/* 弹窗遮罩 */
+.popup-mask {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.5);
+ z-index: 999;
+ display: flex;
+ align-items: flex-end;
+}
+
+/* 弹窗面板 */
+.popup-panel {
+ width: 100%;
+ background: #fff;
+ border-radius: 24rpx 24rpx 0 0;
+ padding: 32rpx;
+ padding-bottom: 0;
+}
+
+.popup-title {
+ font-size: 30rpx;
+ font-weight: 600;
+ color: #2c3e50;
+ margin-bottom: 24rpx;
+ text-align: center;
+}
+
+.popup-scroll {
+ max-height: 400rpx;
+ padding-bottom: 16rpx;
+}
+
+.popup-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16rpx;
+ padding: 0 8rpx;
+}
+
+.popup-item {
+ width: calc((100% - 96rpx) / 7);
+ height: 72rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #f5f7fa;
+ border-radius: 12rpx;
+ font-size: 30rpx;
+ color: #2c3e50;
+ border: 1rpx solid #dce3ec;
+ transition: all 0.15s;
+}
+
+.popup-item:active {
+ background: #5b9bd5;
+ color: #fff;
+ border-color: #5b9bd5;
+}
+
+.popup-cancel {
+ text-align: center;
+ font-size: 28rpx;
+ color: #999;
+ padding: 24rpx 0;
+ padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
+ border-top: 1rpx solid #f0f0f0;
+ margin-top: 16rpx;
+}
diff --git a/pages/appointment/appointment.js b/pages/appointment/appointment.js
index 207180c..ba00d04 100644
--- a/pages/appointment/appointment.js
+++ b/pages/appointment/appointment.js
@@ -80,7 +80,7 @@ Page({
onHostNameInput(e) {
this.setData({ 'form.hostName': e.detail.value })
},
- onPlateNumberInput(e) {
+ onPlateNumberChange(e) {
this.setData({ 'form.plateNumber': e.detail.value })
},
diff --git a/pages/appointment/appointment.json b/pages/appointment/appointment.json
index c69f2e7..e78918d 100644
--- a/pages/appointment/appointment.json
+++ b/pages/appointment/appointment.json
@@ -1,4 +1,6 @@
{
- "usingComponents": {},
+ "usingComponents": {
+ "plate-input": "/components/plate-input/plate-input"
+ },
"navigationBarTitleText": "访客预约"
}
diff --git a/pages/appointment/appointment.wxml b/pages/appointment/appointment.wxml
index eb7203a..b9dfd8e 100644
--- a/pages/appointment/appointment.wxml
+++ b/pages/appointment/appointment.wxml
@@ -4,32 +4,32 @@
预约人信息
- 姓名
+ 姓名*
- 手机号
+ 手机号*
- 公司
+ 公司*
- 来访事由
+ 来访事由*
车牌号
-
+
-
+
- 预约时间
+ 来访时间
- 来访日期
+ 来访日期*
{{form.date || '请选择日期'}}
@@ -38,7 +38,7 @@
- 来访时间
+ 来访时段*
{{form.time || '请选择时间'}}
@@ -52,7 +52,7 @@
被访人信息
- 拜访区域
+ 拜访区域*
{{areaIndex >= 0 ? areas[areaIndex] : '请选择拜访区域'}}
@@ -61,7 +61,7 @@
- 被访人
+ 被访人*
{{personIndex >= 0 ? personNames[personIndex] : '请选择被访人'}}
diff --git a/pages/appointment/appointment.wxss b/pages/appointment/appointment.wxss
index 89ac4b4..67c8387 100644
--- a/pages/appointment/appointment.wxss
+++ b/pages/appointment/appointment.wxss
@@ -44,6 +44,11 @@ page {
flex-shrink: 0;
}
+.required {
+ color: #ff4d4f;
+ margin-left: 4rpx;
+}
+
.form-input {
flex: 1;
font-size: 28rpx;
diff --git a/pages/index/index.wxml b/pages/index/index.wxml
index f6852ff..73309b2 100644
--- a/pages/index/index.wxml
+++ b/pages/index/index.wxml
@@ -26,7 +26,7 @@
访客预约
- 选择预约时间和预约人,提交预约信息
+ 选择来访时间和预约人,提交预约信息
›
diff --git a/pages/records/records.wxml b/pages/records/records.wxml
index 780e029..1679e12 100644
--- a/pages/records/records.wxml
+++ b/pages/records/records.wxml
@@ -45,7 +45,7 @@
{{item.reason}}
- 预约时间
+ 来访时间
{{item.date}} {{item.time}}
diff --git a/pages/scan/result/index.wxml b/pages/scan/result/index.wxml
index 1d4c36a..f75d0d4 100644
--- a/pages/scan/result/index.wxml
+++ b/pages/scan/result/index.wxml
@@ -36,6 +36,10 @@
来访事由
{{record.reason}}
+
+ 车牌号
+ {{record.plateNumber}}
+