From 0d3462a8f5d6d353a3e073122513df6236416922 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=89=8D=E7=AB=AF=E5=B0=8F=E5=95=8A=E7=99=BD?=
<2053890199@qq.com>
Date: Sat, 15 Nov 2025 09:37:56 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E7=BB=93=E5=A9=9A?=
=?UTF-8?q?=E8=AF=81=E9=A2=86=E5=8F=96=E6=B5=81=E7=A8=8B=E5=AE=8C=E6=95=B4?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 添加dayjs依赖用于日期处理
- 新增Dialog组件用于消息提示
- 完善短信验证码发送与校验逻辑
- 实现OCR识别结婚证信息功能
- 完成领取前校验与提交接口对接
- 根据活动状态显示不同界面
---
package.json | 1 +
pnpm-lock.yaml | 8 ++
src/components/Dialog.vue | 251 +++++++++++++++++++++++++++++++++++++
src/components/dialog.ts | 162 ++++++++++++++++++++++++
src/pages/home/index.vue | 207 ++++++++++++++++++------------
src/services/apiService.ts | 10 +-
6 files changed, 558 insertions(+), 81 deletions(-)
create mode 100644 src/components/Dialog.vue
create mode 100644 src/components/dialog.ts
diff --git a/package.json b/package.json
index 301245a..35d0e42 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"dependencies": {
"@tailwindcss/vite": "^4.1.17",
"axios": "^1.13.2",
+ "dayjs": "^1.11.19",
"tailwindcss": "^4.1.17",
"vue": "^3.5.24",
"vue-router": "^4.6.3"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index eea5cec..4264cfe 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -14,6 +14,9 @@ importers:
axios:
specifier: ^1.13.2
version: 1.13.2
+ dayjs:
+ specifier: ^1.11.19
+ version: 1.11.19
tailwindcss:
specifier: ^4.1.17
version: 4.1.17
@@ -530,6 +533,9 @@ packages:
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+ dayjs@1.11.19:
+ resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==}
+
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
@@ -1203,6 +1209,8 @@ snapshots:
csstype@3.1.3: {}
+ dayjs@1.11.19: {}
+
delayed-stream@1.0.0: {}
detect-libc@2.1.2: {}
diff --git a/src/components/Dialog.vue b/src/components/Dialog.vue
new file mode 100644
index 0000000..e8cb813
--- /dev/null
+++ b/src/components/Dialog.vue
@@ -0,0 +1,251 @@
+
+
+
+
+
+
+
+
+
+
+ {{ message }}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/dialog.ts b/src/components/dialog.ts
new file mode 100644
index 0000000..00227f9
--- /dev/null
+++ b/src/components/dialog.ts
@@ -0,0 +1,162 @@
+import { createApp, h, nextTick } from 'vue'
+import Dialog from './Dialog.vue'
+
+// 对话框配置接口
+export interface DialogOptions {
+ // 对话框标题
+ title?: string
+ // 对话框内容
+ message?: string
+ // 是否显示关闭按钮
+ closable?: boolean
+ // 是否显示底部按钮区域
+ showFooter?: boolean
+ // 是否显示取消按钮
+ showCancelButton?: boolean
+ // 确认按钮文本
+ confirmButtonText?: string
+ // 取消按钮文本
+ cancelButtonText?: string
+ // 点击遮罩层是否可以关闭对话框
+ closeOnClickOverlay?: boolean
+ // 确认回调函数
+ onConfirm?: () => void
+ // 取消回调函数
+ onCancel?: () => void
+ // 关闭回调函数
+ onClose?: () => void
+}
+
+// Dialog 实例接口
+interface DialogInstance {
+ show: () => void
+ hide: () => void
+ close: () => void
+}
+
+/**
+ * 创建并显示一个对话框
+ * @param options 对话框配置选项
+ * @returns 对话框实例,可用于手动控制显示和隐藏
+ */
+export function showDialog(options: DialogOptions): DialogInstance {
+ // 默认配置
+ const defaultOptions: DialogOptions = {
+ title: '',
+ message: '',
+ closable: true,
+ showFooter: true,
+ showCancelButton: true,
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ closeOnClickOverlay: true,
+ onConfirm: () => {},
+ onCancel: () => {},
+ onClose: () => {}
+ }
+
+ // 合并配置
+ const mergedOptions = { ...defaultOptions, ...options }
+
+ // 创建一个容器元素
+ const container = document.createElement('div')
+
+ // 对话框状态
+ let visible = true
+
+ // 创建应用实例
+ const app = createApp({
+ render() {
+ return h(Dialog, {
+ visible,
+ title: mergedOptions.title,
+ message: mergedOptions.message,
+ closable: mergedOptions.closable,
+ showFooter: mergedOptions.showFooter,
+ showCancelButton: mergedOptions.showCancelButton,
+ confirmButtonText: mergedOptions.confirmButtonText,
+ cancelButtonText: mergedOptions.cancelButtonText,
+ closeOnClickOverlay: mergedOptions.closeOnClickOverlay,
+ onConfirm: () => {
+ mergedOptions.onConfirm?.()
+ hideDialog()
+ },
+ onCancel: () => {
+ mergedOptions.onCancel?.()
+ hideDialog()
+ },
+ onClose: () => {
+ mergedOptions.onClose?.()
+ hideDialog()
+ }
+ })
+ }
+ })
+
+ // 隐藏对话框
+ function hideDialog() {
+ visible = false
+ // 等待动画完成后卸载组件
+ nextTick(() => {
+ setTimeout(() => {
+ app.unmount()
+ if (container.parentNode) {
+ container.parentNode.removeChild(container)
+ }
+ }, 300)
+ })
+ }
+
+ // 显示对话框(默认为显示状态)
+ function showDialog() {
+ visible = true
+ }
+
+ // 挂载组件
+ app.mount(container)
+ document.body.appendChild(container)
+
+ // 返回控制方法
+ return {
+ show: showDialog,
+ hide: hideDialog,
+ close: hideDialog
+ }
+}
+
+/**
+ * 显示一个确认对话框
+ * @param message 确认消息
+ * @param title 对话框标题
+ * @param onConfirm 确认回调
+ * @returns 对话框实例
+ */
+export function showConfirmDialog(message: string, title: string = '确认', onConfirm?: () => void): DialogInstance {
+ return showDialog({
+ title,
+ message,
+ showCancelButton: true,
+ onConfirm
+ })
+}
+
+/**
+ * 显示一个提示对话框
+ * @param message 提示消息
+ * @param title 对话框标题
+ * @returns 对话框实例
+ */
+export function showAlertDialog(message: string, title: string = '提示'): DialogInstance {
+ return showDialog({
+ title,
+ message,
+ showCancelButton: false
+ })
+}
+
+// 默认导出
+export default {
+ show: showDialog,
+ confirm: showConfirmDialog,
+ alert: showAlertDialog
+}
\ No newline at end of file
diff --git a/src/pages/home/index.vue b/src/pages/home/index.vue
index 348c7b1..44060b0 100644
--- a/src/pages/home/index.vue
+++ b/src/pages/home/index.vue
@@ -26,69 +26,86 @@
-
-
-
-
+
-
-
-
-
-
-
-
-
-
结婚证信息:
-
-
-

-
-
+
活动已结束
-
感谢您的参与,敬请期待下一次活动
-
活动时间:2024年1月1日 - 2024年6月30日
+
【{{ activityInfo.activityName }}】活动已结束,感谢您的参与,敬请期待下一次活动
+
活动时间:{{ activityInfo.activityStartTime }} - {{
+ activityInfo.activityEndTime }}
+
+
+
+
+
+
+
活动获取失败
+
活动获取失败,请稍后重试
+
活动时间:--
@@ -101,20 +118,40 @@
import message from '../../components/message';
import apiService from '../../services/apiService'
import { ref, onMounted } from 'vue'
+import dayjs from 'dayjs'
const ocrUploadId = ref
();
// 表单数据
const formData = ref({
phone: '',
- verificationCode: ''
+ smsCode: '',
+ verifyCode: false, // 验证状态
+ marriageNo: '', // 结婚证号
+ husbandName: '', // 男方姓名
+ wifeName: '', // 女方姓名
+ registerDate: '', // 登记日期
})
+const activityInfo = ref({}); // 活动信息
onMounted(() => {
// 检查活动是否已结束
apiService.getCurrentActivity().then((response: any) => {
- console.log(response);
+ if (response.data) {
+ activityInfo.value = {
+ ...response.data,
+ activityStartTime: dayjs(response.data.activityStartTime).format('YYYY年MM月DD日'),
+ activityEndTime: dayjs(response.data.activityEndTime).format('YYYY年MM月DD日'),
+ };
+ if (new Date(response.data.activityEndTime) < new Date()) {
+ message.error('活动已结束');
+ activityInfo.value.status = 2;
+ }
+ }
+ }).catch((error) => {
+ message.error('获取活动信息失败,请稍后重试')
+ activityInfo.value.status = 3;
})
})
@@ -135,8 +172,11 @@ const sendVerificationCode = () => {
// 调用发送短信验证码接口
apiService.sendSms({
mobile: phone,
- type: 0,
+ type: 3,
}).then(() => {
+ formData.value.verifyCode = false;
+ formData.value.smsCode = '';
+
// 开始倒计时
countdown.value = 60
@@ -161,19 +201,20 @@ const sendVerificationCode = () => {
// 验证验证码
const verifyCode = () => {
- const { verificationCode } = formData.value
+ const { smsCode } = formData.value
- if (verificationCode.length !== 6 || !/^\d{6}$/.test(verificationCode)) {
+ if (smsCode.length !== 6 || !/^\d{6}$/.test(smsCode)) {
message.error('请输入6位数字验证码')
return
}
// 调用验证短信验证码接口
- apiService.login({
+ apiService.verifySms({
mobile: formData.value.phone,
- smsCode: verificationCode,
+ smsCode: smsCode,
+ type: 3,
}).then(() => {
- message.success('验证码验证成功')
+ formData.value.verifyCode = true;
}).catch((error) => {
console.error('验证验证码失败:', error)
message.error('验证码验证失败,请重试')
@@ -196,27 +237,27 @@ const handleImageChange = () => {
formFormData.append('file', file)
apiService.uploadOcrImage(formFormData).then((response: any) => {
- apiService.sendSms({
+ apiService.parseOcrInfo({
mobile: formData.value.phone,
- type: 2, // 2 表示OCR识别 code 获取
- }).then((res) => {
- apiService.parseOcrInfo({
- mobile: formData.value.phone,
- smsCode: res.data,
- uploadId: response.data.uploadId,
- }).then((res) => {
- console.log(res);
- }).catch((error) => {
- console.error('解析OCR信息失败:', error)
- message.error('解析OCR信息失败,请稍后重试')
- })
+ smsCode: formData.value.smsCode,
+ uploadId: response.data.uploadId,
+ }).then((res: any) => {
+ if (res?.data?.parsed?.marriageNo) {
+ formData.value.marriageNo = res?.data?.parsed?.marriageNo;
+ formData.value.husbandName = res?.data?.parsed?.husbandName;
+ formData.value.wifeName = res?.data?.parsed?.wifeName;
+ formData.value.registerDate = res?.data?.parsed?.registerDate;
+ } else {
+ message.error('解析OCR信息失败,请稍后重试');
+ ocrUploadId.value && (ocrUploadId.value.value = '');
+ }
}).catch((error) => {
- console.error('发送验证码失败:', error)
- message.error('验证码发送失败,请稍后重试')
+ message.error('解析OCR信息失败,请稍后重试')
+ ocrUploadId.value && (ocrUploadId.value.value = '');
})
}).catch((error) => {
- console.error('上传OCR图片失败:', error)
message.error('图片上传失败,请稍后重试')
+ ocrUploadId.value && (ocrUploadId.value.value = '');
})
}
@@ -224,14 +265,22 @@ const handleImageChange = () => {
// 提交表单
const submitForm = () => {
- if (!formData.value.phone || !formData.value.verificationCode) {
+ if (!formData.value.phone || !formData.value.smsCode) {
message.error('请完善所有信息')
return
}
- // 模拟提交
- console.log('提交表单数据:', formData.value)
- message.success('提交成功,正在处理您的请求...')
+ apiService.receiveCheck({
+ marriageNo: formData.value.marriageNo,
+ receiveName: formData.value.husbandName,
+ receiveMobile: formData.value.phone,
+ code: formData.value.smsCode,
+ smsCode: formData.value.smsCode,
+ }).then((res: any) => {
+ console.log(res);
+ }).catch((error) => {
+ message.error('领取失败,请稍后重试')
+ })
}
// 组件卸载时清理定时器
diff --git a/src/services/apiService.ts b/src/services/apiService.ts
index f2f8b0c..69f1608 100644
--- a/src/services/apiService.ts
+++ b/src/services/apiService.ts
@@ -53,7 +53,8 @@ export interface MarriageCodeListVO {
export interface CommSmsDTO {
mobile: string
- type: 0 | 1 | 2; // 0=登录;1=兑换领取;2=OCR识别
+ smsCode?: string
+ type: 0 | 1 | 2 | 3; // 0=登录;1=兑换领取;2=OCR识别;3=本流程使用
}
// API服务实现
@@ -79,6 +80,11 @@ export const apiService = {
return request.post('/marriage/common/sms', data)
},
+ // 校验短信验证码
+ verifySms(data: CommSmsDTO) {
+ return request.post('/marriage/common/checkCode', data)
+ },
+
// OCR识别并返回证件信息
parseOcrInfo(data: {
mobile: string
@@ -91,7 +97,7 @@ export const apiService = {
// 领取流程相关接口
// 领取前校验(生成二维码前的校验与预览)
receiveCheck(data: MarriageCodeDTO) {
- return request.post('/marriage/receiveCheck', data)
+ return request.post('/marriage/receiveCheck2', data)
},
// 确认领取(落库并置为已核销)