From 25df88d0ab9d7444ed1d162b9efa1259ac2f6f66 Mon Sep 17 00:00:00 2001
From: longz <longzhaoz@qq.com>
Date: 星期一, 27 四月 2026 10:13:53 +0800
Subject: [PATCH] 小程序对接finish
---
yuyueMiniProgram/src/pages/review/index.vue | 665 ++++++++++++++++++++++++-------------------------------
1 files changed, 291 insertions(+), 374 deletions(-)
diff --git a/yuyueMiniProgram/src/pages/review/index.vue b/yuyueMiniProgram/src/pages/review/index.vue
index 9853c40..141c155 100644
--- a/yuyueMiniProgram/src/pages/review/index.vue
+++ b/yuyueMiniProgram/src/pages/review/index.vue
@@ -1,5 +1,6 @@
<script setup lang="ts">
-import { ref } from 'vue'
+import { cancelMyAppointment, deleteMyAppointment, fetchMyAppointmentDetail } from '@/api/appointment'
+import type { ApprovalFlowNodeItem, MiniMyAppointmentDetailItem } from '@/types/appointment'
definePage({
name: 'review',
@@ -16,51 +17,12 @@
const showCancelModal = ref(false)
const showDeleteModal = ref(false)
-const appointmentStatus = ref('reviewing') // 'reviewing', 'pending_effect', 'effective', 'cancelled', 'invalid', 'rejected'
-
-// 接收页面参数设置初始状态
-import { onLoad } from '@dcloudio/uni-app'
-onLoad((options) => {
- if (options && options.status) {
- appointmentStatus.value = options.status
- }
-})
-
-function handleBack() {
- router.back()
-}
-
-function handleCancel() {
- showCancelModal.value = true
-}
-
-function handleDelete() {
- showDeleteModal.value = true
-}
-
-function confirmCancel() {
- showCancelModal.value = false
- uni.showToast({ title: '已取消预约', icon: 'success' })
- setTimeout(() => {
- router.back()
- }, 1000)
-}
-
-function confirmDelete() {
- showDeleteModal.value = false
- uni.showToast({ title: '已删除记录', icon: 'success' })
- setTimeout(() => {
- router.back()
- }, 1000)
-}
-
-function handleRebook() {
- uni.navigateTo({ url: '/pages/appointment/index' })
-}
-
-function handleViewVisitorCode() {
- uni.navigateTo({ url: '/pages/visitorCode/index' })
-}
+const detail = ref<MiniMyAppointmentDetailItem | null>(null)
+const loading = ref(false)
+const canceling = ref(false)
+const deleting = ref(false)
+const orderId = ref<number>()
+const orderUuid = ref('')
const appointmentIcons = {
male: '/static/appointment/man.png',
@@ -68,342 +30,323 @@
company: '/static/appointment/company.png',
}
-const visitors = [
- {
- id: 1,
- name: '张三',
- gender: 'male',
- phone: '5120**********258',
- company: '成都xxxxxx有限公司',
- plate: '苏U123456'
- },
- {
- id: 2,
- name: '张三',
- gender: 'female',
- phone: '5120**********258',
- company: '成都xxxxxx有限公司'
- },
- {
- id: 3,
- name: '张三',
- gender: 'female',
- phone: '5120**********258',
- company: '成都xxxxxx有限公司'
+const appointmentStatus = computed(() => detail.value?.displayStatus || 'PENDING_VISIT')
+const invalidLike = computed(() => appointmentStatus.value === 'INVALID')
+const headerBg = computed(() => invalidLike.value ? '/static/review/bg-grey.png' : '/static/review/bg-t.png')
+const titleText = computed(() => detail.value?.statusText || '预约记录')
+const showVisitorCodeEntry = computed(() => appointmentStatus.value === 'PENDING_VISIT' || appointmentStatus.value === 'EFFECTIVE')
+
+function handleBack() {
+ router.back()
+}
+
+function handleCancel() {
+ if (!detail.value?.cancelable) {
+ return
}
-]
+ showCancelModal.value = true
+}
+
+async function confirmCancel() {
+ if (!orderId.value || !orderUuid.value || canceling.value) {
+ return
+ }
+ canceling.value = true
+ try {
+ await cancelMyAppointment(orderId.value, orderUuid.value)
+ showCancelModal.value = false
+ uni.showToast({ title: '已取消预约', icon: 'success' })
+ await loadDetail()
+ }
+ catch (error) {
+ uni.showToast({
+ title: error instanceof Error ? error.message : '取消预约失败',
+ icon: 'none',
+ })
+ }
+ finally {
+ canceling.value = false
+ }
+}
+
+function handleRebook() {
+ if (!detail.value) {
+ return
+ }
+ uni.navigateTo({
+ url: `/pages/appointment/index?rebookOrderId=${detail.value.orderId}&rebookOrderUuid=${encodeURIComponent(detail.value.orderUuid)}`,
+ })
+}
+
+function handleDelete() {
+ if (!detail.value?.deletable) {
+ return
+ }
+ showDeleteModal.value = true
+}
+
+async function confirmDelete() {
+ if (!orderId.value || !orderUuid.value || deleting.value) {
+ return
+ }
+ deleting.value = true
+ try {
+ await deleteMyAppointment(orderId.value, orderUuid.value)
+ showDeleteModal.value = false
+ uni.showToast({ title: '已删除记录', icon: 'success' })
+ setTimeout(() => {
+ uni.navigateBack()
+ }, 500)
+ }
+ catch (error) {
+ uni.showToast({
+ title: error instanceof Error ? error.message : '删除记录失败',
+ icon: 'none',
+ })
+ }
+ finally {
+ deleting.value = false
+ }
+}
+
+function handleViewVisitorCode() {
+ uni.switchTab({ url: '/pages/index/index' })
+}
+
+function visitorGenderIcon(gender?: string | null) {
+ return gender === 'FEMALE' ? appointmentIcons.female : appointmentIcons.male
+}
+
+function flowStatusText(status?: string | null) {
+ switch (status) {
+ case 'APPROVED':
+ return '已通过'
+ case 'REJECTED':
+ return '已驳回'
+ case 'CANCELLED':
+ return '已取消'
+ case 'SKIPPED':
+ return '已跳过'
+ case 'PENDING':
+ return '审批中'
+ default:
+ return '待处理'
+ }
+}
+
+function flowStatusClass(status?: string | null) {
+ switch (status) {
+ case 'APPROVED':
+ return 'text-[#52C41A]'
+ case 'REJECTED':
+ return 'text-[#FF4D4F]'
+ case 'CANCELLED':
+ return 'text-[#999999]'
+ case 'PENDING':
+ return 'text-[#0068FF]'
+ default:
+ return 'text-[#999999]'
+ }
+}
+
+function flowUsers(node: ApprovalFlowNodeItem) {
+ return node.groups.flatMap(group => group.users.map(user => ({
+ id: user.taskId,
+ name: user.userName || group.groupName || '审批人',
+ status: user.taskStatus,
+ time: user.actionTime,
+ })))
+}
+
+async function loadDetail() {
+ if (!orderId.value || !orderUuid.value) {
+ uni.showToast({ title: '缺少预约参数', icon: 'none' })
+ return
+ }
+ loading.value = true
+ try {
+ detail.value = await fetchMyAppointmentDetail(orderId.value, orderUuid.value)
+ }
+ catch (error) {
+ uni.showToast({
+ title: error instanceof Error ? error.message : '加载预约详情失败',
+ icon: 'none',
+ })
+ }
+ finally {
+ loading.value = false
+ }
+}
+
+onLoad((options) => {
+ orderId.value = options?.orderId ? Number(options.orderId) : undefined
+ orderUuid.value = options?.orderUuid || ''
+ void loadDetail()
+})
</script>
<template>
<view class="min-h-screen bg-[#F6FBFF] w-full relative box-border flex flex-col pb-[160rpx]">
-
- <!-- 顶部背景图 (被覆盖层) -->
<view class="absolute left-0 top-0 z-0 h-[480rpx] w-full overflow-hidden">
- <image :src="['cancelled', 'invalid', 'rejected'].includes(appointmentStatus) ? '/static/review/bg-grey.png' : '/static/review/bg-t.png'" class="w-full h-full" mode="aspectFill" />
+ <image :src="headerBg" class="w-full h-full" mode="aspectFill" />
</view>
- <!-- 整体内容背景图 (通过 z-index 层级置于顶部背景之上,利用背景图自身弧度产生遮盖效果) -->
<view class="absolute left-0 top-[410rpx] w-full z-0 pointer-events-none" style="height: calc(100% - 380rpx);">
<image src="/static/review/contentbg.png" class="w-full h-full" mode="scaleToFill" />
</view>
- <!-- 自定义导航栏 -->
<view class="relative z-50 w-full shrink-0" :style="{ height: (statusBarHeight + navBarHeight) + 'px' }">
- <!-- 固定在顶部的导航栏 -->
<view class="fixed left-0 top-0 w-full z-50 overflow-hidden" :style="{ height: (statusBarHeight + navBarHeight) + 'px' }">
- <!-- 截取顶部背景图作为 navBar 背景,防止滚动时内容透出 -->
- <image :src="['cancelled', 'invalid', 'rejected'].includes(appointmentStatus) ? '/static/review/bg-grey.png' : '/static/review/bg-t.png'" class="absolute left-0 top-0 w-full z-0" mode="widthFix" />
-
- <view class="flex items-center justify-between w-full absolute left-0 z-10"
- :style="{ top: statusBarHeight + 'px', height: navBarHeight + 'px' }">
+ <image :src="headerBg" class="absolute left-0 top-0 w-full z-0" mode="widthFix" />
+ <view class="flex items-center justify-between w-full absolute left-0 z-10" :style="{ top: statusBarHeight + 'px', height: navBarHeight + 'px' }">
<view class="flex h-full w-[88rpx] items-center justify-center relative z-10" @click="handleBack">
<wd-icon name="arrow-left" size="40rpx" color="#ffffff" />
</view>
<view class="absolute left-0 w-full text-center text-[34rpx] font-medium text-white z-0">
预约记录
</view>
- <view class="w-[88rpx]"></view>
+ <view class="w-[88rpx]" />
</view>
</view>
</view>
- <!-- 内容区 -->
<view class="relative z-10 px-[24rpx] flex-1">
-
- <!-- 审批状态区 -->·
- <view class="px-[24rpx] mb-[108rpx]" v-if="['reviewing', 'rejected'].includes(appointmentStatus)">
- <view class="flex items-center mb-[10rpx]">
- <image v-if="appointmentStatus === 'reviewing'" src="/static/review/chapter.png" class="w-[40rpx] h-[40rpx] mr-[8rpx]" mode="aspectFit" />
- <image v-else-if="appointmentStatus === 'rejected'" src="/static/review/Pending.png" class="w-[40rpx] h-[40rpx] mr-[8rpx]" mode="aspectFit" />
- <text class="text-[32rpx] text-white font-bold">审批中...</text>
- </view>
-
- <!-- 分割线 -->
- <view class="w-full h-[2rpx] bg-white/20 mb-[24rpx]"></view>
+ <view v-if="loading" class="px-[24rpx] pt-[120rpx] text-center text-white text-[28rpx]">
+ 加载中...
+ </view>
- <!-- 进度条模拟 -->
- <view class="flex items-start justify-between relative px-[16rpx]">
+ <template v-else-if="detail">
+ <view class="px-[24rpx] mb-[32rpx]" :class="showVisitorCodeEntry ? '' : 'mt-[76rpx]'">
+ <view class="flex items-center mb-[20rpx]">
+ <image
+ :src="appointmentStatus === 'EFFECTIVE' ? '/static/review/success.png' : invalidLike ? '/static/review/cancel.png' : '/static/review/Pending.png'"
+ class="w-[40rpx] h-[40rpx] mr-[8rpx]"
+ mode="aspectFit"
+ />
+ <text class="text-[32rpx] text-white font-bold">{{ titleText }}</text>
+ </view>
- <!-- 步骤1 -->
- <view class="flex flex-col items-center relative z-10 w-[60rpx]">
- <view class="w-[40rpx] h-[40rpx] rounded-full bg-white flex items-center justify-center mb-[24rpx] relative">
- <!-- 波纹动画层 -->
- <template v-if="['reviewing', 'rejected'].includes(appointmentStatus)">
- <view class="ripple-wave absolute w-full h-full rounded-full bg-white"></view>
- <view class="ripple-wave ripple-delay absolute w-full h-full rounded-full bg-white"></view>
- </template>
- <text class="text-[#0068FF] text-[24rpx] font-bold z-10">1</text>
+ <view class="w-full h-[2rpx] bg-white/30 mb-[24rpx]" />
+
+ <view v-if="showVisitorCodeEntry" class="flex items-center mb-[24rpx]">
+ <view class="bg-[#52C41A] w-full rounded-full h-[60rpx] px-[18rpx] flex items-center justify-center">
+ <text class="text-white text-[26rpx] font-medium">{{ detail.visitTimeText }}</text>
</view>
- <text class="text-white text-[20rpx] mb-[4rpx] whitespace-nowrap">经办人</text>
- <text class="text-white/80 text-[18rpx] whitespace-nowrap">2-3 15:05</text>
</view>
- <!-- 箭头 1 -->
- <view class="flex-1 flex justify-center pt-[0rpx]">
- <image src="/static/review/arrow.png" class="w-[64rpx] h-[40rpx]" mode="aspectFit" />
+ <view v-if="showVisitorCodeEntry" class="flex justify-center mb-[48rpx]">
+ <view class="border-[2rpx] border-solid border-white/60 rounded-full w-[280rpx] h-[64rpx] flex items-center justify-center bg-white/20 transition-opacity active:opacity-70" @click="handleViewVisitorCode">
+ <wd-icon name="view" size="32rpx" color="#ffffff" class="mr-[12rpx]" />
+ <text class="text-white text-[28rpx]">查看访客码</text>
+ </view>
+ </view>
+ </view>
+
+ <view class="flex items-end mb-[26rpx] px-[8rpx]">
+ <text class="text-[32rpx] text-[#000000] font-[500]">拜访信息</text>
+ <text class="text-[24rpx] text-[#676767] font-[350] ml-[16rpx] mb-[4rpx]">您要见的人</text>
+ </view>
+
+ <view class="bg-white rounded-[16rpx] shadow-[0_4rpx_8rpx_rgba(6,47,108,0.1608)] w-full mb-[48rpx] px-[40rpx] py-[12rpx] box-border">
+ <view class="flex flex-col">
+ <view class="flex justify-between items-center h-[96rpx] border-b1">
+ <text class="text-[#000000] text-[28rpx] font-normal">被访人姓名</text>
+ <text class="text-[#666666] text-[28rpx] font-[350]">{{ detail.visitedUserDisplay }}</text>
+ </view>
+ <view class="flex justify-between items-center h-[96rpx] border-b1">
+ <text class="text-[#000000] text-[28rpx] font-normal">拜访事由</text>
+ <text class="text-[#666666] text-[28rpx] font-[350]">{{ detail.visitReasonText }}</text>
+ </view>
+ <view class="flex justify-between items-center h-[96rpx]">
+ <text class="text-[#000000] text-[28rpx] font-normal">拜访时间</text>
+ <text class="text-[#666666] text-[28rpx] font-[350] text-right ml-[24rpx]">{{ detail.visitTimeText }}</text>
+ </view>
+ </view>
+ </view>
+
+ <view class="flex items-end mb-[26rpx] px-[8rpx]">
+ <text class="text-[32rpx] text-[#000000] font-[500]">来访人信息</text>
+ <text class="text-[24rpx] text-[#676767] font-[350] ml-[16rpx] mb-[4rpx]">选择您及同行人员</text>
+ </view>
+
+ <view class="bg-white rounded-[16rpx] shadow-[0_4rpx_8rpx_rgba(6,47,108,0.1608)] w-full mb-[24rpx] box-border pb-[24rpx]">
+ <view class="flex justify-between items-center px-[40rpx] py-[28rpx] border-b1">
+ <text class="text-[#000000] text-[28rpx] font-normal">进场类型</text>
+ <text class="text-[#616161] text-[28rpx] font-[350]">{{ detail.visitTypeText }}</text>
</view>
- <!-- 步骤2 -->
- <view class="flex flex-col items-center relative z-10 w-[60rpx]">
- <view
- class="w-[40rpx] h-[40rpx] rounded-full flex items-center justify-center mb-[24rpx] relative"
- :class="appointmentStatus === 'rejected' ? 'bg-[#FF4D4F]' : 'bg-[#3B72FF]'"
+ <view class="px-[32rpx] py-[16rpx]">
+ <view
+ v-for="(visitor, index) in detail.visitors"
+ :key="visitor.visitorId"
+ class="flex items-center py-[24rpx] border-b2 mb-[16rpx]"
+ :class="index === detail.visitors.length - 1 ? 'last-visitor' : ''"
>
- <template v-if="['reviewing', 'rejected'].includes(appointmentStatus)">
- <!-- 波纹动画层 (蓝底/红底白边) -->
- <view class="ripple-wave absolute w-full h-full rounded-full border-[4rpx] border-solid border-white box-border"></view>
- <view class="ripple-wave ripple-delay absolute w-full h-full rounded-full border-[4rpx] border-solid border-white box-border"></view>
- <!-- 内圈白边 -->
- <view class="absolute w-[40rpx] h-[40rpx] rounded-full border-[2rpx] border-solid border-white top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 box-border z-0"></view>
- <!-- 外圈半透明白边(固定光晕) -->
- <view class="absolute w-[52rpx] h-[52rpx] rounded-full border-[4rpx] border-solid border-white/40 top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 box-border z-0"></view>
- </template>
- <template v-if="appointmentStatus === 'rejected'">
- <!-- 驳回红叉 -->
- <wd-icon name="close" size="24rpx" color="#ffffff" class="z-10" />
- </template>
- <template v-else>
- <text class="text-white text-[24rpx] font-bold z-10">2</text>
- </template>
- </view>
- <text class="text-white text-[20rpx] font-medium whitespace-nowrap">部门负责人</text>
- <text v-if="appointmentStatus === 'rejected'" class="text-white/80 text-[18rpx] whitespace-nowrap">2-3 15:05</text>
- </view>
-
- <!-- 箭头 2 -->
- <view class="flex-1 flex justify-center pt-[0rpx]">
- <image src="/static/review/arrow.png" class="w-[64rpx] h-[40rpx] opacity-40" mode="aspectFit" />
- </view>
-
- <!-- 步骤3 -->
- <view class="flex flex-col items-center relative z-10 w-[60rpx]">
- <view class="w-[40rpx] h-[40rpx] rounded-full bg-white flex items-center justify-center mb-[24rpx]">
- <text class="text-[#989898] text-[24rpx] font-bold">3</text>
- </view>
- <text class="text-white text-[20rpx] whitespace-nowrap">属地单位领导</text>
- </view>
-
- <!-- 箭头 3 -->
- <view class="flex-1 flex justify-center pt-[0rpx]">
- <image src="/static/review/arrow.png" class="w-[64rpx] h-[40rpx] opacity-40" mode="aspectFit" />
- </view>
-
- <!-- 步骤4 -->
- <view class="flex flex-col items-center relative z-10 w-[60rpx]">
- <view class="w-[40rpx] h-[40rpx] rounded-full bg-white flex items-center justify-center mb-[24rpx]">
- <text class="text-[#989898] text-[24rpx] font-bold">4</text>
- </view>
- <text class="text-white text-[20rpx] whitespace-nowrap">访客主管部门</text>
- </view>
-
- <!-- 箭头 4 -->
- <view class="flex-1 flex justify-center pt-[0rpx]">
- <image src="/static/review/arrow.png" class="w-[64rpx] h-[40rpx] opacity-40" mode="aspectFit" />
- </view>
-
- <!-- 步骤5 -->
- <view class="flex flex-col items-center relative z-10 w-[60rpx]">
- <view class="w-[40rpx] h-[40rpx] rounded-full bg-white flex items-center justify-center mb-[24rpx]">
- <text class="text-[#989898] text-[24rpx] font-bold">5</text>
- </view>
- <text class="text-white text-[20rpx] whitespace-nowrap">主管部门领导</text>
- </view>
- </view>
-
- <!-- 驳回提示信息 -->
- <view v-if="appointmentStatus === 'rejected'" class="mt-[16rpx] ml-[-16rpx] w-[702rpx] bg-[rgba(255,230,189,0.6)] border-[2rpx] border-solid border-[#E73232] rounded-full h-[64rpx] flex items-center justify-center box-border relative -left-[8rpx]">
- <wd-icon name="info-circle" size="28rpx" color="#F5222D" class="mr-[12rpx]" />
- <text class="text-[#F5222D] text-[26rpx]">部门领导该日外出,请另外预约</text>
- </view>
- </view>
-
- <!-- 待生效状态区 -->
- <view class="px-[24rpx] mb-[32rpx]" v-if="appointmentStatus === 'pending_effect'">
- <view class="flex items-center mb-[20rpx]">
- <image src="/static/review/Pending.png" class="w-[40rpx] h-[40rpx] mr-[8rpx]" mode="aspectFit" />
- <text class="text-[32rpx] text-white font-bold">待生效...</text>
- </view>
-
- <!-- 分割线 -->
- <view class="w-full h-[2rpx] bg-white/30 mb-[24rpx]"></view>
-
- <!-- 有效期 -->
- <view class="flex items-center mb-[24rpx]">
- <view class="bg-[#52C41A] w-full rounded-full h-[60rpx] px-[18rpx] flex items-center justify-center">
- <text class="text-white text-[28rpx] font-medium">有效期: 2023-10-13 10:00 至 2023-10-13 18:00</text>
- </view>
- </view>
-
- <!-- 查看访客码按钮 -->
- <view class="flex justify-center mb-[85rpx]">
- <view class="border-[2rpx] border-solid border-white/60 rounded-full w-[280rpx] h-[64rpx] flex items-center justify-center bg-white/20 transition-opacity active:opacity-70" @click="handleViewVisitorCode">
- <wd-icon name="view" size="32rpx" color="#ffffff" class="mr-[12rpx]" />
- <text class="text-white text-[28rpx]">查看访客码</text>
- </view>
- </view>
- </view>
-
- <!-- 生效中状态区 -->
- <view class="px-[24rpx] mb-[32rpx]" v-if="appointmentStatus === 'effective'">
- <view class="flex items-center mb-[20rpx]">
- <image src="/static/review/success.png" class="w-[40rpx] h-[40rpx] mr-[8rpx]" mode="aspectFit" />
- <text class="text-[32rpx] text-white font-bold">生效中</text>
- </view>
-
- <!-- 分割线 -->
- <view class="w-full h-[2rpx] bg-white/30 mb-[24rpx]"></view>
-
- <!-- 有效期 -->
- <view class="flex items-center mb-[24rpx]">
- <view class="bg-[#52C41A] w-full rounded-full h-[60rpx] px-[18rpx] flex items-center justify-center">
- <text class="text-white text-[28rpx] font-medium">有效期: 2023-10-13 10:00 至 2023-10-13 18:00</text>
- </view>
- </view>
-
- <!-- 查看访客码按钮 -->
- <view class="flex justify-center mb-[85rpx]">
- <view class="border-[2rpx] border-solid border-white/60 rounded-full w-[280rpx] h-[64rpx] flex items-center justify-center bg-white/20 transition-opacity active:opacity-70" @click="handleViewVisitorCode">
- <wd-icon name="view" size="32rpx" color="#ffffff" class="mr-[12rpx]" />
- <text class="text-white text-[28rpx]">查看访客码</text>
- </view>
- </view>
- </view>
-
- <!-- 已失效/已取消 状态区 -->
- <view class="px-[24rpx] mb-[148rpx] mt-[76rpx] flex flex-col items-center" v-if="['cancelled', 'invalid'].includes(appointmentStatus)">
- <image src="/static/review/cancel.png" class="w-[40rpx] h-[40rpx] mb-[16rpx]" mode="aspectFit" />
- <text class="text-[32rpx] text-white font-bold">{{ appointmentStatus === 'cancelled' ? '已取消' : '已失效' }}</text>
- </view>
-
- <!-- 拜访信息标题 -->
- <view class="flex items-end mb-[26rpx] px-[8rpx]">
- <text class="text-[32rpx] text-[#000000] font-[500]">拜访信息</text>
- <text class="text-[24rpx] text-[#676767] font-[350] ml-[16rpx] mb-[4rpx]">您要见的人</text>
- </view>
-
- <!-- 拜访信息卡片 -->
- <view class="bg-white rounded-[16rpx] shadow-[0_4rpx_8rpx_rgba(6,47,108,0.1608)] w-full mb-[48rpx] px-[40rpx] py-[12rpx] box-border">
- <view class="flex flex-col">
- <view class="flex justify-between items-center h-[96rpx] border-b1">
- <text class="text-[#000000] text-[28rpx] font-normal">被访人姓名</text>
- <text class="text-[#666666] text-[28rpx] font-[350]">员工A(管理部)</text>
- </view>
- <view class="flex justify-between items-center h-[96rpx] border-b1">
- <text class="text-[#000000] text-[28rpx] font-normal">拜访事由</text>
- <text class="text-[#666666] text-[28rpx] font-[350]">xx区域/xx区域</text>
- </view>
- <view class="flex justify-between items-center h-[96rpx]">
- <text class="text-[#000000] text-[28rpx] font-normal">拜访时间</text>
- <text class="text-[#666666] text-[28rpx] font-[350]">2023-10-12 00:00 -2023-10-13 23:59</text>
- </view>
- </view>
- </view>
-
- <!-- 来访人信息标题 -->
- <view class="flex items-end mb-[26rpx] px-[8rpx]">
- <text class="text-[32rpx] text-[#000000] font-[500]">来访人信息</text>
- <text class="text-[24rpx] text-[#676767] font-[350] ml-[16rpx] mb-[4rpx]">选择您及同行人员</text>
- </view>
-
- <!-- 来访人信息卡片 -->
- <view class="bg-white rounded-[16rpx] shadow-[0_4rpx_8rpx_rgba(6,47,108,0.1608)] w-full mb-[24rpx] box-border pb-[24rpx]">
- <view class="flex justify-between items-center px-[40rpx] py-[28rpx] border-b1">
- <text class="text-[#000000] text-[28rpx] font-normal">进场类型</text>
- <text class="text-[#616161] text-[28rpx] font-[350]">人员+车辆</text>
- </view>
-
- <view class="px-[32rpx] py-[16rpx]">
- <view
- v-for="(visitor, index) in visitors"
- :key="visitor.id"
- class="flex items-center py-[24rpx] border-b2 mb-[16rpx]"
- :class="index !== visitors.length - 1 ? '' : ''"
- >
- <text class="text-[#333333] text-[30rpx] font-medium w-[100rpx] pl-[20rpx] shrink-0">{{ visitor.name }}</text>
- <view class="flex flex-col gap-[12rpx] flex-1 min-w-0 pl-[36rpx]">
- <view class="flex items-center text-[#B3B3B3] text-[26rpx]">
- <image :src="visitor.gender === 'male' ? appointmentIcons.male : appointmentIcons.female" class="w-[32rpx] h-[32rpx] mr-[12rpx] shrink-0" mode="aspectFit" />
- <text>{{ visitor.phone }}</text>
- </view>
- <view class="flex items-center text-[#B3B3B3] text-[26rpx]">
- <image :src="appointmentIcons.company" class="w-[32rpx] h-[32rpx] mr-[12rpx] shrink-0" mode="aspectFit" />
- <text class="truncate">{{ visitor.company }}</text>
- </view>
- <view v-if="visitor.plate" class="flex items-center text-[#B3B3B3] text-[26rpx]">
- <view class="w-[28rpx] h-[20rpx] border-[2rpx] border-solid border-[#0068FF] rounded-[4rpx] flex items-center justify-center mr-[12rpx]">
- <text class="text-[#0068FF] text-[12rpx] transform scale-75">NO.</text>
+ <text class="text-[#333333] text-[30rpx] font-medium w-[100rpx] pl-[20rpx] shrink-0">{{ visitor.name }}</text>
+ <view class="flex flex-col gap-[12rpx] flex-1 min-w-0 pl-[36rpx]">
+ <view class="flex items-center text-[#B3B3B3] text-[26rpx]">
+ <image :src="visitorGenderIcon(visitor.gender)" class="w-[32rpx] h-[32rpx] mr-[12rpx] shrink-0" mode="aspectFit" />
+ <text>{{ visitor.mobileMasked || '-' }}</text>
</view>
- <text>{{ visitor.plate }}</text>
+ <view class="flex items-center text-[#B3B3B3] text-[26rpx]">
+ <image :src="appointmentIcons.company" class="w-[32rpx] h-[32rpx] mr-[12rpx] shrink-0" mode="aspectFit" />
+ <text class="truncate">{{ visitor.companyName || '-' }}</text>
+ </view>
+ <view v-if="visitor.plateNo" class="flex items-center text-[#B3B3B3] text-[26rpx]">
+ <view class="w-[28rpx] h-[20rpx] border-[2rpx] border-solid border-[#0068FF] rounded-[4rpx] flex items-center justify-center mr-[12rpx]">
+ <text class="text-[#0068FF] text-[12rpx] transform scale-75">NO.</text>
+ </view>
+ <text>{{ visitor.plateNo }}</text>
+ </view>
</view>
</view>
</view>
</view>
- </view>
- <!-- 提交时间卡片 -->
- <view class="bg-white rounded-[16rpx] shadow-[0_4rpx_8rpx_rgba(6,47,108,0.1608)] w-full mb-[32rpx] px-[40rpx] py-[12rpx] box-border">
- <view class="flex flex-col">
- <view class="flex justify-between items-center h-[96rpx]" :class="(appointmentStatus !== 'reviewing' && appointmentStatus !== 'invalid') ? 'border-b1' : ''">
- <text class="text-[#000000] text-[28rpx] font-normal">提交时间</text>
- <text class="text-[#666666] text-[28rpx] font-[350]">2023-10-13 12:00</text>
- </view>
- <view v-if="['pending_effect', 'effective'].includes(appointmentStatus)" class="flex justify-between items-center h-[96rpx]">
- <text class="text-[#000000] text-[28rpx] font-normal">审核通过时间</text>
- <text class="text-[#666666] text-[28rpx] font-[350]">2023-10-13 12:00</text>
- </view>
- <view v-if="appointmentStatus === 'cancelled'" class="flex justify-between items-center h-[96rpx]">
- <text class="text-[#000000] text-[28rpx] font-normal">取消时间</text>
- <text class="text-[#666666] text-[28rpx] font-[350]">2023-10-13 12:00</text>
+ <view class="flex items-end mb-[26rpx] px-[8rpx]">
+ <text class="text-[32rpx] text-[#000000] font-[500]">审批情况</text>
+ </view>
+
+ <view class="bg-white rounded-[16rpx] shadow-[0_4rpx_8rpx_rgba(6,47,108,0.1608)] w-full mb-[32rpx] px-[40rpx] py-[24rpx] box-border">
+ <view v-for="node in detail.flowTree" :key="node.nodeCode" class="py-[20rpx]" :class="node !== detail.flowTree[detail.flowTree.length - 1] ? 'border-b1' : ''">
+ <view class="flex items-center justify-between mb-[12rpx]">
+ <text class="text-[#000000] text-[28rpx] font-medium">{{ node.nodeName }}</text>
+ <text class="text-[24rpx]" :class="flowStatusClass(node.nodeStatus)">{{ flowStatusText(node.nodeStatus) }}</text>
+ </view>
+ <view v-for="user in flowUsers(node)" :key="user.id" class="flex items-center justify-between py-[8rpx]">
+ <text class="text-[#666666] text-[24rpx]">{{ user.name }}</text>
+ <text class="text-[#999999] text-[22rpx]">{{ user.time ? user.time.replace('T', ' ').slice(0, 16) : flowStatusText(user.status) }}</text>
+ </view>
</view>
</view>
- </view>
+
+ <view class="bg-white rounded-[16rpx] shadow-[0_4rpx_8rpx_rgba(6,47,108,0.1608)] w-full mb-[32rpx] px-[40rpx] py-[12rpx] box-border">
+ <view class="flex justify-between items-center h-[96rpx]">
+ <text class="text-[#000000] text-[28rpx] font-normal">提交时间</text>
+ <text class="text-[#666666] text-[28rpx] font-[350]">{{ detail.createTime.replace('T', ' ').slice(0, 16) }}</text>
+ </view>
+ </view>
+ </template>
</view>
- <!-- 底部操作按钮 -->
- <view class="fixed bottom-0 left-0 w-[750rpx] h-[108rpx] bg-[#FFFFFF] rounded-t-[20rpx] box-content pb-[env(safe-area-inset-bottom)] z-[100] shadow-[inset_0_2rpx_0_0_#E1E1E1] flex justify-end items-center gap-[32rpx]" >
- <view
- v-if="appointmentStatus === 'reviewing'"
+ <view class="fixed bottom-0 left-0 w-[750rpx] h-[108rpx] bg-[#FFFFFF] rounded-t-[20rpx] box-content pb-[env(safe-area-inset-bottom)] z-[100] shadow-[inset_0_2rpx_0_0_#E1E1E1] flex justify-end items-center gap-[32rpx]">
+ <view
+ v-if="detail?.cancelable"
class="w-[240rpx] h-[76rpx] rounded-full flex items-center justify-center bg-[#F5F5F5] transition-opacity active:opacity-70"
@click="handleCancel"
>
<image src="/static/review/reduce.png" class="w-[40rpx] h-[40rpx] mr-[8rpx]" mode="aspectFit" />
<text class="text-[30rpx] text-[#999999] font-medium">取消预约</text>
</view>
- <view
- v-if="appointmentStatus === 'rejected'"
- class="w-[240rpx] h-[76rpx] rounded-full flex items-center justify-center bg-white border-[2rpx] border-solid border-[#0068FF] transition-opacity active:opacity-70 box-border"
- >
- <text class="text-[30rpx] text-[#0068FF] font-medium">重新提交</text>
- </view>
- <view
- v-if="['cancelled', 'invalid'].includes(appointmentStatus)"
+ <view
+ v-else-if="detail?.deletable"
class="w-[240rpx] h-[76rpx] rounded-full flex items-center justify-center bg-[#F5F5F5] transition-opacity active:opacity-70"
@click="handleDelete"
>
- <image src="/static/appointment/delete.png" class="w-[40rpx] h-[40rpx] mr-[8rpx]" mode="aspectFit" />
- <text class="text-[30rpx] text-[#999999] font-medium">删除</text>
+ <wd-icon name="delete-thin" size="32rpx" color="#999999" class="mr-[8rpx]" />
+ <text class="text-[30rpx] text-[#999999] font-medium">删除记录</text>
</view>
- <view
+ <view
class="w-[240rpx] h-[76rpx] mr-[40rpx] rounded-full flex items-center justify-center bg-[#0068FF] shadow-[0_8rpx_24rpx_rgba(0,104,255,0.2)] transition-opacity active:opacity-70"
@click="handleRebook"
>
@@ -412,49 +355,36 @@
</view>
</view>
- <!-- 取消预约弹窗 -->
<wd-popup v-model="showCancelModal" custom-style="border-radius: 32rpx; background: transparent;" :safe-area-inset-bottom="false">
<view class="w-[600rpx] bg-white rounded-[32rpx] flex flex-col items-center pt-[48rpx] pb-[48rpx] px-[40rpx] box-border relative overflow-hidden" style="background: linear-gradient(180deg, #EBF4FF 0%, #FFFFFF 40%);">
<text class="text-[34rpx] text-[#333333] font-bold mb-[32rpx]">提示</text>
<image src="/static/review/cancelIcon.png" class="w-[202rpx] h-[202rpx] mb-[32rpx]" mode="aspectFit" />
<text class="text-[30rpx] text-[#333333] mb-[64rpx]">是否取消本次预约</text>
-
+
<view class="flex w-full justify-center gap-[32rpx]">
- <view
- class="w-[212rpx] h-[80rpx] rounded-full bg-[#F5F5F5] flex items-center justify-center transition-opacity active:opacity-70"
- @click="showCancelModal = false"
- >
+ <view class="w-[212rpx] h-[80rpx] rounded-full bg-[#F5F5F5] flex items-center justify-center transition-opacity active:opacity-70" @click="showCancelModal = false">
<text class="text-[#999999] text-[30rpx]">再想想</text>
</view>
- <view
- class="w-[212rpx] h-[80rpx] rounded-full bg-[#0068FF] flex items-center justify-center transition-opacity active:opacity-70"
- @click="confirmCancel"
- >
- <text class="text-white text-[30rpx]">确认取消</text>
+ <view class="w-[212rpx] h-[80rpx] rounded-full bg-[#0068FF] flex items-center justify-center transition-opacity active:opacity-70" @click="confirmCancel">
+ <text class="text-white text-[30rpx]">{{ canceling ? '取消中...' : '确认取消' }}</text>
</view>
</view>
</view>
</wd-popup>
- <!-- 删除记录弹窗 -->
<wd-popup v-model="showDeleteModal" custom-style="border-radius: 32rpx; background: transparent;" :safe-area-inset-bottom="false">
<view class="w-[600rpx] bg-white rounded-[32rpx] flex flex-col items-center pt-[48rpx] pb-[48rpx] px-[40rpx] box-border relative overflow-hidden" style="background: linear-gradient(180deg, #EBF4FF 0%, #FFFFFF 40%);">
<text class="text-[34rpx] text-[#333333] font-bold mb-[32rpx]">提示</text>
- <image src="/static/review/cancelIcon.png" class="w-[202rpx] h-[202rpx] mb-[32rpx]" mode="aspectFit" />
- <text class="text-[30rpx] text-[#333333] mb-[64rpx]">是否有确认删除此记录?</text>
-
+ <wd-icon name="delete-thin" size="120rpx" color="#999999" class="mb-[32rpx]" />
+ <text class="text-[30rpx] text-[#333333] mb-[24rpx]">删除后将不再出现在我的预约记录中</text>
+ <text class="text-[24rpx] text-[#999999] mb-[64rpx]">仅当前账号隐藏,不影响后台查看</text>
+
<view class="flex w-full justify-center gap-[32rpx]">
- <view
- class="w-[212rpx] h-[80rpx] rounded-full bg-[#F5F5F5] flex items-center justify-center transition-opacity active:opacity-70"
- @click="showDeleteModal = false"
- >
- <text class="text-[#999999] text-[30rpx]">再想想</text>
+ <view class="w-[212rpx] h-[80rpx] rounded-full bg-[#F5F5F5] flex items-center justify-center transition-opacity active:opacity-70" @click="showDeleteModal = false">
+ <text class="text-[#999999] text-[30rpx]">取消</text>
</view>
- <view
- class="w-[212rpx] h-[80rpx] rounded-full bg-[#0068FF] flex items-center justify-center transition-opacity active:opacity-70"
- @click="confirmDelete"
- >
- <text class="text-white text-[30rpx]">确认删除</text>
+ <view class="w-[212rpx] h-[80rpx] rounded-full bg-[#0068FF] flex items-center justify-center transition-opacity active:opacity-70" @click="confirmDelete">
+ <text class="text-white text-[30rpx]">{{ deleting ? '删除中...' : '确认删除' }}</text>
</view>
</view>
</view>
@@ -463,34 +393,21 @@
</template>
<style scoped lang="scss">
-.border-b1{
+.border-b1 {
border-bottom: 2rpx solid #F5F5F5;
}
-.border-b2{
+.border-b2 {
border-bottom: 2rpx dashed #F5F5F5;
- &:last-child{
+ &:last-child {
border-bottom: none;
margin-bottom: 0;
}
}
-@keyframes ripple {
- 0% {
- transform: scale(1);
- opacity: 0.6;
- }
- 100% {
- transform: scale(1.6);
- opacity: 0;
- }
-}
-.ripple-wave {
- animation: ripple 2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
+.last-visitor {
+ border-bottom: none;
+ margin-bottom: 0;
}
-
-.ripple-delay {
- animation-delay: 1s;
-}
-</style>
\ No newline at end of file
+</style>
--
Gitblit v1.7.1