调整目录结构和路由跳转
This commit is contained in:
1 parent
3a0117f4ba
commit
d6a3b55911
16 files changed
+937
-1026
No files matched your search
+3
-27
@@ -85,35 +85,11 @@ const tabbar: TabbarItem[] = [
|
||||
auth: ["merchant"],
|
||||
},
|
||||
{
|
||||
pagePath: "pages/tabbar/invitation",
|
||||
text: "访客邀约",
|
||||
iconPath: "/static/tabbar/invitation.png",
|
||||
selectedIconPath: "/static/tabbar/invitation-select.png",
|
||||
launchParam: ["invitation"],
|
||||
auth: [],
|
||||
},
|
||||
{
|
||||
pagePath: "pages/tabbar/invitationRecord",
|
||||
text: "邀约记录",
|
||||
iconPath: "/static/tabbar/order.png",
|
||||
selectedIconPath: "/static/tabbar/order-select.png",
|
||||
launchParam: ["invitation"],
|
||||
auth: [],
|
||||
},
|
||||
{
|
||||
pagePath: "pages/tabbar/message",
|
||||
text: "通知公告",
|
||||
iconPath: "/static/tabbar/message.png",
|
||||
selectedIconPath: "/static/tabbar/message-select.png",
|
||||
launchParam: ["message"],
|
||||
auth: [],
|
||||
},
|
||||
{
|
||||
pagePath: "pages/integrated/index",
|
||||
pagePath: "pages/tabbar/integrated",
|
||||
text: "综合服务",
|
||||
iconPath: "/static/tabbar/integrated.png",
|
||||
selectedIconPath: "/static/tabbar/integrated-select.png",
|
||||
launchParam: [],
|
||||
launchParam: ["integrated"],
|
||||
auth: [],
|
||||
},
|
||||
{
|
||||
@@ -121,7 +97,7 @@ const tabbar: TabbarItem[] = [
|
||||
text: "我的",
|
||||
iconPath: "/static/tabbar/my.png",
|
||||
selectedIconPath: "/static/tabbar/my-select.png",
|
||||
launchParam: ["canteen", "selfMerchant", "onlineShop", "coopMerchant"],
|
||||
launchParam: ["canteen", "selfMerchant", "onlineShop", "coopMerchant", "integrated"],
|
||||
auth: ["user", "merchant", "doorAdmin"],
|
||||
},
|
||||
]
|
||||
|
||||
+12
-55
@@ -73,23 +73,9 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/tabbar/invitation",
|
||||
"path": "pages/tabbar/integrated",
|
||||
"style": {
|
||||
"navigationBarTitleText": "访客",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/tabbar/invitationRecord",
|
||||
"style": {
|
||||
"navigationBarTitleText": "访客记录",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/tabbar/message",
|
||||
"style": {
|
||||
"navigationBarTitleText": "通知公告",
|
||||
"navigationBarTitleText": "综合服务",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
@@ -414,17 +400,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/invitation",
|
||||
"pages": [
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "访客详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/thirdApp",
|
||||
"pages": [
|
||||
@@ -439,12 +414,6 @@
|
||||
{
|
||||
"root": "pages/integrated",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "综合服务"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "lostAndFound/index",
|
||||
"style": {
|
||||
@@ -494,15 +463,21 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "visitor/index",
|
||||
"path": "visitor/invitation",
|
||||
"style": {
|
||||
"navigationBarTitleText": "访客管理"
|
||||
"navigationBarTitleText": "访客邀约"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "visitor/invitationRecord",
|
||||
"style": {
|
||||
"navigationBarTitleText": "邀约记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "visitor/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "访客详情"
|
||||
"navigationBarTitleText": "邀约详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -596,25 +571,7 @@
|
||||
"selectedIconPath": ""
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/tabbar/invitation",
|
||||
"text": "",
|
||||
"iconPath": "",
|
||||
"selectedIconPath": ""
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/tabbar/invitationRecord",
|
||||
"text": "",
|
||||
"iconPath": "",
|
||||
"selectedIconPath": ""
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/tabbar/message",
|
||||
"text": "",
|
||||
"iconPath": "",
|
||||
"selectedIconPath": ""
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/integrated/index",
|
||||
"pagePath": "pages/tabbar/integrated",
|
||||
"text": "",
|
||||
"iconPath": "",
|
||||
"selectedIconPath": ""
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
<template>
|
||||
<div class="integrated-title-card">
|
||||
<div class="integrated-title">综合服务</div>
|
||||
</div>
|
||||
<div class="service-container-card">
|
||||
<div class="service-container">
|
||||
<div class="service-grid">
|
||||
<div
|
||||
v-for="item in services"
|
||||
:key="item.name"
|
||||
class="service-item"
|
||||
@click="goPage(item)"
|
||||
>
|
||||
<image :src="item.icon" class="service-icon" />
|
||||
<div class="service-label">{{ item.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const services = [
|
||||
{
|
||||
name: 'todo',
|
||||
label: '工作待办',
|
||||
icon: '/src/static/icon/todo.png',
|
||||
url: '/pages/integrated/todo/index'
|
||||
},
|
||||
{
|
||||
name: 'meeting-booking',
|
||||
label: '会议预定',
|
||||
icon: '/src/static/icon/meeting-booking.png',
|
||||
url: '/pages/integrated/meeting/index'
|
||||
},
|
||||
{
|
||||
name: 'lost-and-found',
|
||||
label: '失物招领',
|
||||
icon: '/src/static/icon/lost-and-found.png',
|
||||
url: '/pages/integrated/lostAndFound/index'
|
||||
},
|
||||
{
|
||||
name: 'feedback',
|
||||
label: '意见反馈',
|
||||
icon: '/src/static/icon/feedback.png',
|
||||
url: '/pages/integrated/feedback/index'
|
||||
},
|
||||
{
|
||||
name: 'repair-report',
|
||||
label: '维修上报',
|
||||
icon: '/src/static/icon/repair-report.png',
|
||||
url: '/pages/integrated/repair/index'
|
||||
},
|
||||
{
|
||||
name: 'notice',
|
||||
label: '通知公告',
|
||||
icon: '/src/static/icon/notice.png',
|
||||
url: '/pages/integrated/notice/index'
|
||||
},
|
||||
{
|
||||
name: 'visitor',
|
||||
label: '访客管理',
|
||||
icon: '/src/static/icon/visitor.png',
|
||||
url: '/pages/integrated/visitor/index'
|
||||
}
|
||||
]
|
||||
|
||||
function goPage(item) {
|
||||
if (item.url) {
|
||||
uni.navigateTo({ url: item.url })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.integrated-title-card {
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.06);
|
||||
margin: 32rpx 24rpx 0 24rpx;
|
||||
padding: 0 0 8rpx 0;
|
||||
}
|
||||
.integrated-title {
|
||||
font-size: 38rpx;
|
||||
font-weight: bold;
|
||||
color: #222;
|
||||
text-align: center;
|
||||
padding: 36rpx 0 24rpx 0;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
.service-container-card {
|
||||
background: #fff;
|
||||
border-radius: 24rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.06);
|
||||
margin: 24rpx;
|
||||
padding-bottom: 32rpx;
|
||||
}
|
||||
.service-container {
|
||||
padding: 32rpx 0 0 0;
|
||||
background: transparent;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
.service-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
padding: 0 24rpx;
|
||||
}
|
||||
.service-item {
|
||||
width: 25%;
|
||||
margin-bottom: 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
.service-item:hover {
|
||||
transform: translateY(-6rpx) scale(1.06);
|
||||
box-shadow: 0 2rpx 12rpx rgba(25,118,210,0.08);
|
||||
}
|
||||
.service-icon {
|
||||
width: 92rpx;
|
||||
height: 92rpx;
|
||||
margin-bottom: 14rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #f5f7fa;
|
||||
box-shadow: 0 2rpx 8rpx rgba(25,118,210,0.04);
|
||||
transition: box-shadow 0.2s;
|
||||
}
|
||||
.service-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
body {
|
||||
background: #f5f6fa;
|
||||
}
|
||||
</style>
|
||||
@@ -1,236 +1,105 @@
|
||||
<template>
|
||||
<view class="visitor-detail">
|
||||
<view class="detail-header">
|
||||
<view class="visitor-info">
|
||||
<text class="visitor-name">{{ detail.visitorName }}</text>
|
||||
<text class="visitor-phone">{{ detail.visitorPhone }}</text>
|
||||
</view>
|
||||
<view class="status-tag" :class="getStatusClass(detail.status)">{{ getStatusText(detail.status) }}</view>
|
||||
</view>
|
||||
|
||||
<view class="detail-content">
|
||||
<view class="info-row">
|
||||
<text class="label">来访目的:</text>
|
||||
<text class="value">{{ getPurposeLabel(detail.purpose) }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="label">被访人:</text>
|
||||
<text class="value">{{ detail.hostName }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="label">来访时间:</text>
|
||||
<text class="value">{{ formatVisitTime(detail.visitDate, detail.visitTime) }}</text>
|
||||
</view>
|
||||
<view v-if="detail.remark" class="info-row">
|
||||
<text class="label">备注说明:</text>
|
||||
<text class="value">{{ detail.remark }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="detail.rejectReason" class="reject-section">
|
||||
<view class="reject-title">拒绝原因</view>
|
||||
<view class="reject-content">{{ detail.rejectReason }}</view>
|
||||
</view>
|
||||
|
||||
<view class="detail-footer">
|
||||
<text class="apply-time">申请时间:{{ formatTime(detail.createTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<crud-layout title="详情" mainIsScroll bg="/static/page/blue-bg.png">
|
||||
<view v-if="detail.id">
|
||||
<tm-sheet :margin="[0, 20]" class="second-text-32">
|
||||
<tm-text font-size="32">访客信息</tm-text>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>访客姓名:</text>
|
||||
<text>{{ detail.name }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>访客手机号:</text>
|
||||
<text>{{ detail.mobile }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>来访公司名称:</text>
|
||||
<text>{{ detail.companyName }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>来访原因:</text>
|
||||
<text>{{ visitorReasonList.find((item) => item.id == detail.reasonValue)?.title || "" }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>接待人:</text>
|
||||
<text>{{ detail.userName }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>来访人数:</text>
|
||||
<text>{{ detail.peopleNumber }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>是否可随行人员:</text>
|
||||
<text>{{ detail.isOtherPeople == "1" ? "是" : "否" }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>是否可驾驶车辆:</text>
|
||||
<text>{{ detail.isDrive == "1" ? "是" : "否" }}</text>
|
||||
</view>
|
||||
</tm-sheet>
|
||||
|
||||
<tm-sheet :margin="[0, 20]" class="second-text-32">
|
||||
<tm-text font-size="32">时间</tm-text>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>预计来访时间:</text>
|
||||
<text>{{ detail.vendDate }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>预计离开时间:</text>
|
||||
<text>{{ detail.vstartDate }}</text>
|
||||
</view>
|
||||
</tm-sheet>
|
||||
|
||||
<tm-sheet :margin="[0, 20]" class="second-text-32">
|
||||
<tm-text font-size="32">其他</tm-text>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>创建方式:</text>
|
||||
<text>{{ detail.type == "1" ? "主动申请" : detail.type == "2" ? "邀约" : "后台创建" }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>提交时间:</text>
|
||||
<text>{{ detail.createTime }}</text>
|
||||
</view>
|
||||
</tm-sheet>
|
||||
</view>
|
||||
|
||||
<view class="h-40rpx" />
|
||||
</crud-layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import meetingRoomApi from '@/sheep/api/meetingRoom'
|
||||
import { onMounted, ref } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { invitationApi } from "@/sheep/api"
|
||||
|
||||
const detail = ref<any>({})
|
||||
|
||||
const purposeOptions = [
|
||||
{ value: '1', label: '商务洽谈' },
|
||||
{ value: '2', label: '技术交流' },
|
||||
{ value: '3', label: '面试' },
|
||||
{ value: '4', label: '参观访问' },
|
||||
{ value: '5', label: '其他' }
|
||||
]
|
||||
|
||||
const timeOptions = [
|
||||
{ value: '1', label: '上午 (9:00-12:00)' },
|
||||
{ value: '2', label: '下午 (14:00-18:00)' },
|
||||
{ value: '3', label: '全天 (9:00-18:00)' }
|
||||
]
|
||||
|
||||
function getPurposeLabel(purpose: string) {
|
||||
const option = purposeOptions.find(item => item.value === purpose)
|
||||
return option ? option.label : '其他'
|
||||
}
|
||||
|
||||
function getStatusText(status: string) {
|
||||
const statusMap: Record<string, string> = {
|
||||
'1': '待审核',
|
||||
'2': '已通过',
|
||||
'3': '已拒绝',
|
||||
'4': '已取消',
|
||||
'5': '已完成'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
|
||||
function getStatusClass(status: string) {
|
||||
const classMap: Record<string, string> = {
|
||||
'1': 'status-pending',
|
||||
'2': 'status-approved',
|
||||
'3': 'status-rejected',
|
||||
'4': 'status-cancelled',
|
||||
'5': 'status-completed'
|
||||
}
|
||||
return classMap[status] || 'status-pending'
|
||||
}
|
||||
|
||||
function formatVisitTime(date: string, time: string) {
|
||||
const timeLabel = timeOptions.find(item => item.value === time)?.label || ''
|
||||
return `${date} ${timeLabel}`
|
||||
}
|
||||
|
||||
function formatTime(time: string) {
|
||||
if (!time) return ''
|
||||
return new Date(time).toLocaleString()
|
||||
}
|
||||
const visitorReasonList = ref<{ title: string; id: string }[]>([])
|
||||
|
||||
onLoad(async (options: any) => {
|
||||
const id = options.id
|
||||
if (!id) return
|
||||
|
||||
try {
|
||||
const response: any = await meetingRoomApi.getVisitorDetail(id)
|
||||
if (response.code === 0 && response.data) {
|
||||
detail.value = response.data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取访客详情失败:', error)
|
||||
uni.showToast({ title: '获取详情失败', icon: 'none' })
|
||||
}
|
||||
const id = options.id
|
||||
|
||||
try {
|
||||
const { code, data, msg } = await invitationApi.getInvitationDetail(id)
|
||||
if (code == 0) {
|
||||
detail.value = data
|
||||
return
|
||||
}
|
||||
uni.showToast({ title: msg || "获取详情失败", icon: "none" })
|
||||
} catch (error: any) {
|
||||
uni.showToast({ title: error.message, icon: "none" })
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getVisitorReasonList()
|
||||
})
|
||||
|
||||
// 获取拜访原因列表
|
||||
const getVisitorReasonList = async () => {
|
||||
const { code, data } = await invitationApi.getDictListByType("1")
|
||||
if (code == 0 && data) {
|
||||
visitorReasonList.value = data.map((item: any) => ({ title: item.label, id: item.value }))
|
||||
return
|
||||
}
|
||||
visitorReasonList.value = []
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.visitor-detail {
|
||||
padding: 32rpx;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 24rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.visitor-info {
|
||||
.visitor-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.visitor-phone {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
padding: 12rpx 24rpx;
|
||||
border-radius: 24rpx;
|
||||
font-size: 26rpx;
|
||||
|
||||
&.status-pending {
|
||||
background: #fff3e0;
|
||||
color: #f57c00;
|
||||
}
|
||||
|
||||
&.status-approved {
|
||||
background: #e8f5e8;
|
||||
color: #388e3c;
|
||||
}
|
||||
|
||||
&.status-rejected {
|
||||
background: #ffebee;
|
||||
color: #d32f2f;
|
||||
}
|
||||
|
||||
&.status-cancelled {
|
||||
background: #f5f5f5;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
&.status-completed {
|
||||
background: #e3f2fd;
|
||||
color: #1976d2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
width: 160rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reject-section {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.reject-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #d32f2f;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.reject-content {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-footer {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
|
||||
.apply-time {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,438 +0,0 @@
|
||||
<template>
|
||||
<view class="visitor-container">
|
||||
<!-- 访客申请表单 -->
|
||||
<view class="visitor-form">
|
||||
<view class="form-title">访客申请</view>
|
||||
<view class="form-item">
|
||||
<view class="label">访客姓名</view>
|
||||
<input v-model="visitorName" placeholder="请输入访客姓名" class="name-input" />
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="label">访客手机号</view>
|
||||
<input v-model="visitorPhone" placeholder="请输入访客手机号" class="phone-input" />
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="label">来访目的</view>
|
||||
<picker @change="onPurposeChange" :value="purposeIndex" :range="purposeOptions" range-key="label">
|
||||
<view class="picker">{{ purposeOptions[purposeIndex].label }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="label">来访时间</view>
|
||||
<picker mode="date" @change="onDateChange" :value="visitDate">
|
||||
<view class="picker">{{ visitDate || '请选择来访日期' }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="label">来访时段</view>
|
||||
<picker @change="onTimeChange" :value="timeIndex" :range="timeOptions" range-key="label">
|
||||
<view class="picker">{{ timeOptions[timeIndex].label }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="label">被访人</view>
|
||||
<input v-model="hostName" placeholder="请输入被访人姓名" class="host-input" />
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="label">备注说明</view>
|
||||
<textarea
|
||||
v-model="remark"
|
||||
placeholder="请输入备注说明(选填)"
|
||||
class="remark-textarea"
|
||||
maxlength="200"
|
||||
/>
|
||||
<view class="char-count">{{ remark.length }}/200</view>
|
||||
</view>
|
||||
<button @click="submitVisitor" class="submit-btn" :disabled="!canSubmit">
|
||||
提交申请
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 访客记录列表 -->
|
||||
<view class="visitor-list">
|
||||
<view class="list-title">访客记录</view>
|
||||
<view v-if="visitorList.length === 0" class="empty-tip">
|
||||
暂无访客记录
|
||||
</view>
|
||||
<view v-else>
|
||||
<view
|
||||
v-for="item in visitorList"
|
||||
:key="item.id"
|
||||
class="visitor-item"
|
||||
@click="viewDetail(item)"
|
||||
>
|
||||
<view class="item-header">
|
||||
<view class="visitor-info">
|
||||
<text class="visitor-name">{{ item.visitorName }}</text>
|
||||
<text class="visitor-phone">{{ item.visitorPhone }}</text>
|
||||
</view>
|
||||
<view class="status-tag" :class="getStatusClass(item.status)">{{ getStatusText(item.status) }}</view>
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<view class="purpose">来访目的:{{ getPurposeLabel(item.purpose) }}</view>
|
||||
<view class="host">被访人:{{ item.hostName }}</view>
|
||||
<view class="time">来访时间:{{ formatVisitTime(item.visitDate, item.visitTime) }}</view>
|
||||
</view>
|
||||
<view class="item-footer">
|
||||
<text class="apply-time">申请时间:{{ formatTime(item.createTime) }}</text>
|
||||
<text v-if="item.remark" class="has-remark">有备注</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import meetingRoomApi from '@/sheep/api/meetingRoom'
|
||||
|
||||
const purposeOptions = [
|
||||
{ value: '1', label: '商务洽谈' },
|
||||
{ value: '2', label: '技术交流' },
|
||||
{ value: '3', label: '面试' },
|
||||
{ value: '4', label: '参观访问' },
|
||||
{ value: '5', label: '其他' }
|
||||
]
|
||||
|
||||
const timeOptions = [
|
||||
{ value: '1', label: '上午 (9:00-12:00)' },
|
||||
{ value: '2', label: '下午 (14:00-18:00)' },
|
||||
{ value: '3', label: '全天 (9:00-18:00)' }
|
||||
]
|
||||
|
||||
const visitorName = ref('')
|
||||
const visitorPhone = ref('')
|
||||
const purposeIndex = ref(0)
|
||||
const visitDate = ref('')
|
||||
const timeIndex = ref(0)
|
||||
const hostName = ref('')
|
||||
const remark = ref('')
|
||||
const visitorList = ref<any[]>([])
|
||||
|
||||
const canSubmit = computed(() => {
|
||||
return visitorName.value.trim() &&
|
||||
visitorPhone.value.trim() &&
|
||||
visitDate.value &&
|
||||
hostName.value.trim()
|
||||
})
|
||||
|
||||
function onPurposeChange(e: any) {
|
||||
purposeIndex.value = e.detail.value
|
||||
}
|
||||
|
||||
function onDateChange(e: any) {
|
||||
visitDate.value = e.detail.value
|
||||
}
|
||||
|
||||
function onTimeChange(e: any) {
|
||||
timeIndex.value = e.detail.value
|
||||
}
|
||||
|
||||
function getPurposeLabel(purpose: string) {
|
||||
const option = purposeOptions.find(item => item.value === purpose)
|
||||
return option ? option.label : '其他'
|
||||
}
|
||||
|
||||
function getStatusText(status: string) {
|
||||
const statusMap: Record<string, string> = {
|
||||
'1': '待审核',
|
||||
'2': '已通过',
|
||||
'3': '已拒绝',
|
||||
'4': '已取消',
|
||||
'5': '已完成'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
|
||||
function getStatusClass(status: string) {
|
||||
const classMap: Record<string, string> = {
|
||||
'1': 'status-pending',
|
||||
'2': 'status-approved',
|
||||
'3': 'status-rejected',
|
||||
'4': 'status-cancelled',
|
||||
'5': 'status-completed'
|
||||
}
|
||||
return classMap[status] || 'status-pending'
|
||||
}
|
||||
|
||||
function formatVisitTime(date: string, time: string) {
|
||||
const timeLabel = timeOptions.find(item => item.value === time)?.label || ''
|
||||
return `${date} ${timeLabel}`
|
||||
}
|
||||
|
||||
function formatTime(time: string) {
|
||||
if (!time) return ''
|
||||
return new Date(time).toLocaleDateString()
|
||||
}
|
||||
|
||||
async function submitVisitor() {
|
||||
if (!canSubmit.value) {
|
||||
uni.showToast({ title: '请填写完整信息', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 验证手机号格式
|
||||
const phoneRegex = /^1[3-9]\d{9}$/
|
||||
if (!phoneRegex.test(visitorPhone.value)) {
|
||||
uni.showToast({ title: '请输入正确的手机号', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
uni.showLoading({ title: '提交中...' })
|
||||
|
||||
const data = {
|
||||
visitorName: visitorName.value.trim(),
|
||||
visitorPhone: visitorPhone.value.trim(),
|
||||
purpose: purposeOptions[purposeIndex.value].value,
|
||||
visitDate: visitDate.value,
|
||||
visitTime: timeOptions[timeIndex.value].value,
|
||||
hostName: hostName.value.trim(),
|
||||
remark: remark.value.trim()
|
||||
}
|
||||
|
||||
const response: any = await meetingRoomApi.submitVisitor(data)
|
||||
|
||||
uni.hideLoading()
|
||||
|
||||
if (response.code === 0) {
|
||||
uni.showToast({ title: '提交成功', icon: 'success' })
|
||||
|
||||
// 清空表单
|
||||
visitorName.value = ''
|
||||
visitorPhone.value = ''
|
||||
purposeIndex.value = 0
|
||||
visitDate.value = ''
|
||||
timeIndex.value = 0
|
||||
hostName.value = ''
|
||||
remark.value = ''
|
||||
|
||||
// 刷新列表
|
||||
loadVisitorList()
|
||||
} else {
|
||||
uni.showToast({ title: response.msg || '提交失败', icon: 'none' })
|
||||
}
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '提交失败', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
function viewDetail(item: any) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/integrated/visitor/detail?id=${item.id}`
|
||||
})
|
||||
}
|
||||
|
||||
async function loadVisitorList() {
|
||||
try {
|
||||
const response: any = await meetingRoomApi.getVisitorList({
|
||||
current: 1,
|
||||
size: 20
|
||||
})
|
||||
|
||||
if (response.code === 0 && response.data) {
|
||||
visitorList.value = response.data.records || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载访客记录失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadVisitorList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.visitor-container {
|
||||
padding: 24rpx;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.visitor-form {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.form-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.picker {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
padding: 0 24rpx;
|
||||
background: #f7f8fa;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.name-input,
|
||||
.phone-input,
|
||||
.host-input {
|
||||
height: 80rpx;
|
||||
padding: 0 24rpx;
|
||||
background: #f7f8fa;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.remark-textarea {
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
padding: 24rpx;
|
||||
background: #f7f8fa;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.char-count {
|
||||
text-align: right;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
border-radius: 8rpx;
|
||||
font-size: 32rpx;
|
||||
|
||||
&:disabled {
|
||||
background: #ccc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.visitor-list {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
|
||||
.list-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
padding: 60rpx 0;
|
||||
}
|
||||
|
||||
.visitor-item {
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
padding: 24rpx 0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.visitor-info {
|
||||
.visitor-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.visitor-phone {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 24rpx;
|
||||
|
||||
&.status-pending {
|
||||
background: #fff3e0;
|
||||
color: #f57c00;
|
||||
}
|
||||
|
||||
&.status-approved {
|
||||
background: #e8f5e8;
|
||||
color: #388e3c;
|
||||
}
|
||||
|
||||
&.status-rejected {
|
||||
background: #ffebee;
|
||||
color: #d32f2f;
|
||||
}
|
||||
|
||||
&.status-cancelled {
|
||||
background: #f5f5f5;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
&.status-completed {
|
||||
background: #e3f2fd;
|
||||
color: #1976d2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-content {
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.purpose,
|
||||
.host,
|
||||
.time {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 8rpx;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
|
||||
.item-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.apply-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.has-remark {
|
||||
font-size: 24rpx;
|
||||
color: #007aff;
|
||||
background: #e3f2fd;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -105,9 +105,6 @@ const _timestr = ref("2025-01-01")
|
||||
const visitorReasonList = ref<{ title: string; id: string }[]>([])
|
||||
|
||||
onLoad(() => {
|
||||
const app = getApp()
|
||||
app._initTabbar()
|
||||
|
||||
getVisitorReasonList()
|
||||
})
|
||||
|
||||
+18
-19
@@ -59,23 +59,27 @@
|
||||
<view v-if="v.checkStatus == '5'" class="p-1 c-white! sub-text-26 rounded-1 bg-#f5222d">已取消</view>
|
||||
<view class="sub-text-26">{{ v.vstartDate + " ~ " + v.vendDate }}</view>
|
||||
</view>
|
||||
<view class="flex justify-between my-1 px-2 py-4 bg-#ECF4F9 rounded-4">
|
||||
<view class="flex-col justify-start sub-text-30 font-italic whitespace-nowrap">
|
||||
<view>来访人:{{ v.name }}</view>
|
||||
<view>手机号:{{ v.mobile }}</view>
|
||||
<view class="flex-col my-1 px-4 py-2 bg-#ECF4F9 rounded-4">
|
||||
<view class="flex justify-start sub-text-30 whitespace-nowrap">
|
||||
<view>{{ v.name }}</view>
|
||||
<view class="second-text-28 ml-2">{{ v.mobile }}</view>
|
||||
</view>
|
||||
<view class="flex-col second-text-28">
|
||||
<span v-if="state.params.type == 1">接待人:{{ v.userName }}</span>
|
||||
<view class="flex justify-center sub-text-28 font-italic whitespace-nowrap my-2">
|
||||
<span>拜访原因:{{ visitorReasonList.find((item) => item.id == v.reasonValue)?.title || "" }}</span>
|
||||
</view>
|
||||
<view class="flex justify-end second-text-28 whitespace-nowrap">
|
||||
<span v-if="state.params.type == 1">接待人:{{ v.userName }}</span>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="v.checkStatus == 1" class="flex justify-end items-center gap-2">
|
||||
<tm-modal title="确定审核通过吗?" height="auto" @confirm="visitorCheck(v.id, 2)">
|
||||
<template v-slot:trigger><tm-button class="px-1" size="s">审核通过</tm-button></template>
|
||||
</tm-modal>
|
||||
<tm-modal title="确定审核拒绝吗?" height="auto" @confirm="visitorCheck(v.id, 3)">
|
||||
<template v-slot:trigger><tm-button class="px-1" size="s" color="danger">审核拒绝</tm-button></template>
|
||||
</tm-modal>
|
||||
<view class="flex justify-end items-center gap-2">
|
||||
<view v-if="v.checkStatus == 1" class="flex items-center gap-2">
|
||||
<tm-modal title="确定审核通过吗?" height="auto" @confirm="visitorCheck(v.id, 2)">
|
||||
<template v-slot:trigger><tm-button class="px-1" size="s">审核通过</tm-button></template>
|
||||
</tm-modal>
|
||||
<tm-modal title="确定审核拒绝吗?" height="auto" @confirm="visitorCheck(v.id, 3)">
|
||||
<template v-slot:trigger><tm-button class="px-1" size="s" color="danger">审核拒绝</tm-button></template>
|
||||
</tm-modal>
|
||||
</view>
|
||||
<tm-button class="px-1" size="s" color="success" @click.stop="goDetail(v)">查看详情</tm-button>
|
||||
</view>
|
||||
</view>
|
||||
@@ -85,7 +89,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from "vue"
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app"
|
||||
import { onShow } from "@dcloudio/uni-app"
|
||||
import { hooks, router } from "@@/index"
|
||||
import zTabs from "@@/components/other/z-tabs/z-tabs.vue"
|
||||
import { invitationApi } from "@/sheep/api"
|
||||
@@ -107,11 +111,6 @@ const state = reactive<any>({
|
||||
const pageRef = ref<any>(null)
|
||||
const visitorReasonList = ref<{ title: string; id: string }[]>([])
|
||||
|
||||
onLoad(() => {
|
||||
const app = getApp()
|
||||
app._initTabbar()
|
||||
})
|
||||
|
||||
onShow(async () => {
|
||||
const isLogin = await hooks.useCheckLogin()
|
||||
if (!isLogin) return
|
||||
@@ -0,0 +1,236 @@
|
||||
<template>
|
||||
<view class="visitor-detail">
|
||||
<view class="detail-header">
|
||||
<view class="visitor-info">
|
||||
<text class="visitor-name">{{ detail.visitorName }}</text>
|
||||
<text class="visitor-phone">{{ detail.visitorPhone }}</text>
|
||||
</view>
|
||||
<view class="status-tag" :class="getStatusClass(detail.status)">{{ getStatusText(detail.status) }}</view>
|
||||
</view>
|
||||
|
||||
<view class="detail-content">
|
||||
<view class="info-row">
|
||||
<text class="label">来访目的:</text>
|
||||
<text class="value">{{ getPurposeLabel(detail.purpose) }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="label">被访人:</text>
|
||||
<text class="value">{{ detail.hostName }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="label">来访时间:</text>
|
||||
<text class="value">{{ formatVisitTime(detail.visitDate, detail.visitTime) }}</text>
|
||||
</view>
|
||||
<view v-if="detail.remark" class="info-row">
|
||||
<text class="label">备注说明:</text>
|
||||
<text class="value">{{ detail.remark }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="detail.rejectReason" class="reject-section">
|
||||
<view class="reject-title">拒绝原因</view>
|
||||
<view class="reject-content">{{ detail.rejectReason }}</view>
|
||||
</view>
|
||||
|
||||
<view class="detail-footer">
|
||||
<text class="apply-time">申请时间:{{ formatTime(detail.createTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import meetingRoomApi from '@/sheep/api/meetingRoom'
|
||||
|
||||
const detail = ref<any>({})
|
||||
|
||||
const purposeOptions = [
|
||||
{ value: '1', label: '商务洽谈' },
|
||||
{ value: '2', label: '技术交流' },
|
||||
{ value: '3', label: '面试' },
|
||||
{ value: '4', label: '参观访问' },
|
||||
{ value: '5', label: '其他' }
|
||||
]
|
||||
|
||||
const timeOptions = [
|
||||
{ value: '1', label: '上午 (9:00-12:00)' },
|
||||
{ value: '2', label: '下午 (14:00-18:00)' },
|
||||
{ value: '3', label: '全天 (9:00-18:00)' }
|
||||
]
|
||||
|
||||
function getPurposeLabel(purpose: string) {
|
||||
const option = purposeOptions.find(item => item.value === purpose)
|
||||
return option ? option.label : '其他'
|
||||
}
|
||||
|
||||
function getStatusText(status: string) {
|
||||
const statusMap: Record<string, string> = {
|
||||
'1': '待审核',
|
||||
'2': '已通过',
|
||||
'3': '已拒绝',
|
||||
'4': '已取消',
|
||||
'5': '已完成'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
|
||||
function getStatusClass(status: string) {
|
||||
const classMap: Record<string, string> = {
|
||||
'1': 'status-pending',
|
||||
'2': 'status-approved',
|
||||
'3': 'status-rejected',
|
||||
'4': 'status-cancelled',
|
||||
'5': 'status-completed'
|
||||
}
|
||||
return classMap[status] || 'status-pending'
|
||||
}
|
||||
|
||||
function formatVisitTime(date: string, time: string) {
|
||||
const timeLabel = timeOptions.find(item => item.value === time)?.label || ''
|
||||
return `${date} ${timeLabel}`
|
||||
}
|
||||
|
||||
function formatTime(time: string) {
|
||||
if (!time) return ''
|
||||
return new Date(time).toLocaleString()
|
||||
}
|
||||
|
||||
onLoad(async (options: any) => {
|
||||
const id = options.id
|
||||
if (!id) return
|
||||
|
||||
try {
|
||||
const response: any = await meetingRoomApi.getVisitorDetail(id)
|
||||
if (response.code === 0 && response.data) {
|
||||
detail.value = response.data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取访客详情失败:', error)
|
||||
uni.showToast({ title: '获取详情失败', icon: 'none' })
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.visitor-detail {
|
||||
padding: 32rpx;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 24rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.visitor-info {
|
||||
.visitor-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.visitor-phone {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
padding: 12rpx 24rpx;
|
||||
border-radius: 24rpx;
|
||||
font-size: 26rpx;
|
||||
|
||||
&.status-pending {
|
||||
background: #fff3e0;
|
||||
color: #f57c00;
|
||||
}
|
||||
|
||||
&.status-approved {
|
||||
background: #e8f5e8;
|
||||
color: #388e3c;
|
||||
}
|
||||
|
||||
&.status-rejected {
|
||||
background: #ffebee;
|
||||
color: #d32f2f;
|
||||
}
|
||||
|
||||
&.status-cancelled {
|
||||
background: #f5f5f5;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
&.status-completed {
|
||||
background: #e3f2fd;
|
||||
color: #1976d2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
width: 160rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reject-section {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.reject-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #d32f2f;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.reject-content {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-footer {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
|
||||
.apply-time {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,421 @@
|
||||
<template>
|
||||
<view class="visitor-container">
|
||||
<!-- 访客申请表单 -->
|
||||
<view class="visitor-form">
|
||||
<view class="form-title">访客申请</view>
|
||||
<view class="form-item">
|
||||
<view class="label">访客姓名</view>
|
||||
<input v-model="visitorName" placeholder="请输入访客姓名" class="name-input" />
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="label">访客手机号</view>
|
||||
<input v-model="visitorPhone" placeholder="请输入访客手机号" class="phone-input" />
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="label">来访目的</view>
|
||||
<picker @change="onPurposeChange" :value="purposeIndex" :range="purposeOptions" range-key="label">
|
||||
<view class="picker">{{ purposeOptions[purposeIndex].label }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="label">来访时间</view>
|
||||
<picker mode="date" @change="onDateChange" :value="visitDate">
|
||||
<view class="picker">{{ visitDate || "请选择来访日期" }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="label">来访时段</view>
|
||||
<picker @change="onTimeChange" :value="timeIndex" :range="timeOptions" range-key="label">
|
||||
<view class="picker">{{ timeOptions[timeIndex].label }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="label">被访人</view>
|
||||
<input v-model="hostName" placeholder="请输入被访人姓名" class="host-input" />
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="label">备注说明</view>
|
||||
<textarea v-model="remark" placeholder="请输入备注说明(选填)" class="remark-textarea" maxlength="200" />
|
||||
<view class="char-count">{{ remark.length }}/200</view>
|
||||
</view>
|
||||
<button @click="submitVisitor" class="submit-btn" :disabled="!canSubmit">提交申请</button>
|
||||
</view>
|
||||
|
||||
<!-- 访客记录列表 -->
|
||||
<view class="visitor-list">
|
||||
<view class="list-title">访客记录</view>
|
||||
<view v-if="visitorList.length === 0" class="empty-tip"> 暂无访客记录 </view>
|
||||
<view v-else>
|
||||
<view v-for="item in visitorList" :key="item.id" class="visitor-item" @click="viewDetail(item)">
|
||||
<view class="item-header">
|
||||
<view class="visitor-info">
|
||||
<text class="visitor-name">{{ item.visitorName }}</text>
|
||||
<text class="visitor-phone">{{ item.visitorPhone }}</text>
|
||||
</view>
|
||||
<view class="status-tag" :class="getStatusClass(item.status)">{{ getStatusText(item.status) }}</view>
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<view class="purpose">来访目的:{{ getPurposeLabel(item.purpose) }}</view>
|
||||
<view class="host">被访人:{{ item.hostName }}</view>
|
||||
<view class="time">来访时间:{{ formatVisitTime(item.visitDate, item.visitTime) }}</view>
|
||||
</view>
|
||||
<view class="item-footer">
|
||||
<text class="apply-time">申请时间:{{ formatTime(item.createTime) }}</text>
|
||||
<text v-if="item.remark" class="has-remark">有备注</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from "vue"
|
||||
import meetingRoomApi from "@/sheep/api/meetingRoom"
|
||||
|
||||
const purposeOptions = [
|
||||
{ value: "1", label: "商务洽谈" },
|
||||
{ value: "2", label: "技术交流" },
|
||||
{ value: "3", label: "面试" },
|
||||
{ value: "4", label: "参观访问" },
|
||||
{ value: "5", label: "其他" },
|
||||
]
|
||||
|
||||
const timeOptions = [
|
||||
{ value: "1", label: "上午 (9:00-12:00)" },
|
||||
{ value: "2", label: "下午 (14:00-18:00)" },
|
||||
{ value: "3", label: "全天 (9:00-18:00)" },
|
||||
]
|
||||
|
||||
const visitorName = ref("")
|
||||
const visitorPhone = ref("")
|
||||
const purposeIndex = ref(0)
|
||||
const visitDate = ref("")
|
||||
const timeIndex = ref(0)
|
||||
const hostName = ref("")
|
||||
const remark = ref("")
|
||||
const visitorList = ref<any[]>([])
|
||||
|
||||
const canSubmit = computed(() => {
|
||||
return visitorName.value.trim() && visitorPhone.value.trim() && visitDate.value && hostName.value.trim()
|
||||
})
|
||||
|
||||
function onPurposeChange(e: any) {
|
||||
purposeIndex.value = e.detail.value
|
||||
}
|
||||
|
||||
function onDateChange(e: any) {
|
||||
visitDate.value = e.detail.value
|
||||
}
|
||||
|
||||
function onTimeChange(e: any) {
|
||||
timeIndex.value = e.detail.value
|
||||
}
|
||||
|
||||
function getPurposeLabel(purpose: string) {
|
||||
const option = purposeOptions.find((item) => item.value === purpose)
|
||||
return option ? option.label : "其他"
|
||||
}
|
||||
|
||||
function getStatusText(status: string) {
|
||||
const statusMap: Record<string, string> = {
|
||||
"1": "待审核",
|
||||
"2": "已通过",
|
||||
"3": "已拒绝",
|
||||
"4": "已取消",
|
||||
"5": "已完成",
|
||||
}
|
||||
return statusMap[status] || "未知"
|
||||
}
|
||||
|
||||
function getStatusClass(status: string) {
|
||||
const classMap: Record<string, string> = {
|
||||
"1": "status-pending",
|
||||
"2": "status-approved",
|
||||
"3": "status-rejected",
|
||||
"4": "status-cancelled",
|
||||
"5": "status-completed",
|
||||
}
|
||||
return classMap[status] || "status-pending"
|
||||
}
|
||||
|
||||
function formatVisitTime(date: string, time: string) {
|
||||
const timeLabel = timeOptions.find((item) => item.value === time)?.label || ""
|
||||
return `${date} ${timeLabel}`
|
||||
}
|
||||
|
||||
function formatTime(time: string) {
|
||||
if (!time) return ""
|
||||
return new Date(time).toLocaleDateString()
|
||||
}
|
||||
|
||||
async function submitVisitor() {
|
||||
if (!canSubmit.value) {
|
||||
uni.showToast({ title: "请填写完整信息", icon: "none" })
|
||||
return
|
||||
}
|
||||
|
||||
// 验证手机号格式
|
||||
const phoneRegex = /^1[3-9]\d{9}$/
|
||||
if (!phoneRegex.test(visitorPhone.value)) {
|
||||
uni.showToast({ title: "请输入正确的手机号", icon: "none" })
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
uni.showLoading({ title: "提交中..." })
|
||||
|
||||
const data = {
|
||||
visitorName: visitorName.value.trim(),
|
||||
visitorPhone: visitorPhone.value.trim(),
|
||||
purpose: purposeOptions[purposeIndex.value].value,
|
||||
visitDate: visitDate.value,
|
||||
visitTime: timeOptions[timeIndex.value].value,
|
||||
hostName: hostName.value.trim(),
|
||||
remark: remark.value.trim(),
|
||||
}
|
||||
|
||||
const response: any = await meetingRoomApi.submitVisitor(data)
|
||||
|
||||
uni.hideLoading()
|
||||
|
||||
if (response.code === 0) {
|
||||
uni.showToast({ title: "提交成功", icon: "success" })
|
||||
|
||||
// 清空表单
|
||||
visitorName.value = ""
|
||||
visitorPhone.value = ""
|
||||
purposeIndex.value = 0
|
||||
visitDate.value = ""
|
||||
timeIndex.value = 0
|
||||
hostName.value = ""
|
||||
remark.value = ""
|
||||
|
||||
// 刷新列表
|
||||
loadVisitorList()
|
||||
} else {
|
||||
uni.showToast({ title: response.msg || "提交失败", icon: "none" })
|
||||
}
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: "提交失败", icon: "none" })
|
||||
}
|
||||
}
|
||||
|
||||
function viewDetail(item: any) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/integrated/visitor/detail?id=${item.id}`,
|
||||
})
|
||||
}
|
||||
|
||||
async function loadVisitorList() {
|
||||
try {
|
||||
const response: any = await meetingRoomApi.getVisitorList({
|
||||
current: 1,
|
||||
size: 20,
|
||||
})
|
||||
|
||||
if (response.code === 0 && response.data) {
|
||||
visitorList.value = response.data.records || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载访客记录失败:", error)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadVisitorList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.visitor-container {
|
||||
padding: 24rpx;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.visitor-form {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.form-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.picker {
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
padding: 0 24rpx;
|
||||
background: #f7f8fa;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.name-input,
|
||||
.phone-input,
|
||||
.host-input {
|
||||
height: 80rpx;
|
||||
padding: 0 24rpx;
|
||||
background: #f7f8fa;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.remark-textarea {
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
padding: 24rpx;
|
||||
background: #f7f8fa;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.char-count {
|
||||
text-align: right;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
border-radius: 8rpx;
|
||||
font-size: 32rpx;
|
||||
|
||||
&:disabled {
|
||||
background: #ccc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.visitor-list {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
|
||||
.list-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
padding: 60rpx 0;
|
||||
}
|
||||
|
||||
.visitor-item {
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
padding: 24rpx 0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.visitor-info {
|
||||
.visitor-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.visitor-phone {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 24rpx;
|
||||
|
||||
&.status-pending {
|
||||
background: #fff3e0;
|
||||
color: #f57c00;
|
||||
}
|
||||
|
||||
&.status-approved {
|
||||
background: #e8f5e8;
|
||||
color: #388e3c;
|
||||
}
|
||||
|
||||
&.status-rejected {
|
||||
background: #ffebee;
|
||||
color: #d32f2f;
|
||||
}
|
||||
|
||||
&.status-cancelled {
|
||||
background: #f5f5f5;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
&.status-completed {
|
||||
background: #e3f2fd;
|
||||
color: #1976d2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-content {
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.purpose,
|
||||
.host,
|
||||
.time {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 8rpx;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
|
||||
.item-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.apply-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.has-remark {
|
||||
font-size: 24rpx;
|
||||
color: #007aff;
|
||||
background: #e3f2fd;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
File renamed without changes.
@@ -1,105 +0,0 @@
|
||||
<template>
|
||||
<crud-layout title="详情" mainIsScroll bg="/static/page/blue-bg.png">
|
||||
<view v-if="detail.id">
|
||||
<tm-sheet :margin="[0, 20]" class="second-text-32">
|
||||
<tm-text font-size="32">访客信息</tm-text>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>访客姓名:</text>
|
||||
<text>{{ detail.name }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>访客手机号:</text>
|
||||
<text>{{ detail.mobile }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>来访公司名称:</text>
|
||||
<text>{{ detail.companyName }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>来访原因:</text>
|
||||
<text>{{ visitorReasonList.find((item) => item.id == detail.reasonValue)?.title || "" }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>接待人:</text>
|
||||
<text>{{ detail.userName }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>来访人数:</text>
|
||||
<text>{{ detail.peopleNumber }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>是否可随行人员:</text>
|
||||
<text>{{ detail.isOtherPeople == "1" ? "是" : "否" }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>是否可驾驶车辆:</text>
|
||||
<text>{{ detail.isDrive == "1" ? "是" : "否" }}</text>
|
||||
</view>
|
||||
</tm-sheet>
|
||||
|
||||
<tm-sheet :margin="[0, 20]" class="second-text-32">
|
||||
<tm-text font-size="32">时间</tm-text>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>预计来访时间:</text>
|
||||
<text>{{ detail.vendDate }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>预计离开时间:</text>
|
||||
<text>{{ detail.vstartDate }}</text>
|
||||
</view>
|
||||
</tm-sheet>
|
||||
|
||||
<tm-sheet :margin="[0, 20]" class="second-text-32">
|
||||
<tm-text font-size="32">其他</tm-text>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>创建方式:</text>
|
||||
<text>{{ detail.type == "1" ? "主动申请" : detail.type == "2" ? "邀约" : "后台创建" }}</text>
|
||||
</view>
|
||||
<view class="flex justify-between mt-1">
|
||||
<text>提交时间:</text>
|
||||
<text>{{ detail.createTime }}</text>
|
||||
</view>
|
||||
</tm-sheet>
|
||||
</view>
|
||||
|
||||
<view class="h-40rpx" />
|
||||
</crud-layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue"
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
import { invitationApi } from "@/sheep/api"
|
||||
|
||||
const detail = ref<any>({})
|
||||
const visitorReasonList = ref<{ title: string; id: string }[]>([])
|
||||
|
||||
onLoad(async (options: any) => {
|
||||
const id = options.id
|
||||
|
||||
try {
|
||||
const { code, data, msg } = await invitationApi.getInvitationDetail(id)
|
||||
if (code == 0) {
|
||||
detail.value = data
|
||||
return
|
||||
}
|
||||
uni.showToast({ title: msg || "获取详情失败", icon: "none" })
|
||||
} catch (error: any) {
|
||||
uni.showToast({ title: error.message, icon: "none" })
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getVisitorReasonList()
|
||||
})
|
||||
|
||||
// 获取拜访原因列表
|
||||
const getVisitorReasonList = async () => {
|
||||
const { code, data } = await invitationApi.getDictListByType("1")
|
||||
if (code == 0 && data) {
|
||||
visitorReasonList.value = data.map((item: any) => ({ title: item.label, id: item.value }))
|
||||
return
|
||||
}
|
||||
visitorReasonList.value = []
|
||||
}
|
||||
</script>
|
||||
@@ -40,19 +40,7 @@ const moduleList = [
|
||||
launchParam: "flowStatistics",
|
||||
},
|
||||
{
|
||||
pagePath: "/pages/tabbar/invitation",
|
||||
text: "访客",
|
||||
iconPath: "/static/tabbar/invitation-select.png",
|
||||
launchParam: "invitation",
|
||||
},
|
||||
{
|
||||
pagePath: "/pages/tabbar/message",
|
||||
text: "通知公告",
|
||||
iconPath: "/static/tabbar/message-select.png",
|
||||
launchParam: "message",
|
||||
},
|
||||
{
|
||||
pagePath: "/pages/integrated/index",
|
||||
pagePath: "/pages/tabbar/integrated",
|
||||
text: "综合服务",
|
||||
iconPath: "/static/tabbar/integrated-select.png",
|
||||
launchParam: "integrated",
|
||||
@@ -87,6 +75,10 @@ const jumpByParam = async () => {
|
||||
uni.setStorageSync("launchParam", launchParam)
|
||||
uni.switchTab({ url: "/pages/tabbar/coopMerchant" })
|
||||
break
|
||||
case "integrated": // 综合服务
|
||||
uni.setStorageSync("launchParam", launchParam)
|
||||
uni.switchTab({ url: "/pages/tabbar/integrated" })
|
||||
break
|
||||
default:
|
||||
uni.hideTabBar()
|
||||
break
|
||||
@@ -117,6 +109,10 @@ const jumpByParam = async () => {
|
||||
uni.setStorageSync("launchParam", launchParam)
|
||||
return uni.reLaunch({ url: "/pages/tabbar/coopMerchant" })
|
||||
}
|
||||
if (launchParam === "integrated") {
|
||||
uni.setStorageSync("launchParam", launchParam)
|
||||
return uni.reLaunch({ url: "/pages/tabbar/integrated" })
|
||||
}
|
||||
case "doorAdmin":
|
||||
return uni.switchTab({ url: "/pages/tabbar/cabinet" })
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<crud-layout bg="/static/page/blue-bg.png">
|
||||
<div class="integrated-title-card">
|
||||
<div class="integrated-title">综合服务</div>
|
||||
</div>
|
||||
<div class="service-container-card">
|
||||
<div class="service-container">
|
||||
<div class="service-grid">
|
||||
<div v-for="item in services" :key="item.name" class="service-item" @click="goPage(item)">
|
||||
<image :src="item.icon" class="service-icon" />
|
||||
<div class="service-label">{{ item.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</crud-layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onLoad } from "@dcloudio/uni-app"
|
||||
|
||||
const services = [
|
||||
{
|
||||
name: "todo",
|
||||
label: "工作待办",
|
||||
icon: "/src/static/icon/todo.png",
|
||||
url: "/pages/integrated/todo/index",
|
||||
},
|
||||
{
|
||||
name: "meeting-booking",
|
||||
label: "会议预定",
|
||||
icon: "/src/static/icon/meeting-booking.png",
|
||||
url: "/pages/integrated/meeting/index",
|
||||
},
|
||||
{
|
||||
name: "lost-and-found",
|
||||
label: "失物招领",
|
||||
icon: "/src/static/icon/lost-and-found.png",
|
||||
url: "/pages/integrated/lostAndFound/index",
|
||||
},
|
||||
{
|
||||
name: "feedback",
|
||||
label: "意见反馈",
|
||||
icon: "/src/static/icon/feedback.png",
|
||||
url: "/pages/integrated/feedback/index",
|
||||
},
|
||||
{
|
||||
name: "repair-report",
|
||||
label: "维修上报",
|
||||
icon: "/src/static/icon/repair-report.png",
|
||||
url: "/pages/integrated/repair/index",
|
||||
},
|
||||
{
|
||||
name: "notice",
|
||||
label: "通知公告",
|
||||
icon: "/src/static/icon/notice.png",
|
||||
url: "/pages/integrated/notice/index",
|
||||
},
|
||||
{
|
||||
name: "visitor",
|
||||
label: "访客管理",
|
||||
icon: "/src/static/icon/visitor.png",
|
||||
url: "/pages/integrated/visitor/invitation",
|
||||
},
|
||||
]
|
||||
|
||||
onLoad(() => {
|
||||
const app = getApp()
|
||||
app._initTabbar()
|
||||
})
|
||||
|
||||
function goPage(item) {
|
||||
if (item.url) {
|
||||
uni.navigateTo({ url: item.url })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.integrated-title-card {
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
||||
margin: 32rpx 24rpx 0 24rpx;
|
||||
padding: 0 0 8rpx 0;
|
||||
}
|
||||
.integrated-title {
|
||||
font-size: 38rpx;
|
||||
font-weight: bold;
|
||||
color: #222;
|
||||
text-align: center;
|
||||
padding: 36rpx 0 24rpx 0;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
.service-container-card {
|
||||
background: #fff;
|
||||
border-radius: 24rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
||||
margin: 24rpx;
|
||||
padding-bottom: 32rpx;
|
||||
}
|
||||
.service-container {
|
||||
padding: 32rpx 0 0 0;
|
||||
background: transparent;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
.service-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
padding: 0 24rpx;
|
||||
}
|
||||
.service-item {
|
||||
width: 25%;
|
||||
margin-bottom: 40rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
.service-item:hover {
|
||||
transform: translateY(-6rpx) scale(1.06);
|
||||
box-shadow: 0 2rpx 12rpx rgba(25, 118, 210, 0.08);
|
||||
}
|
||||
.service-icon {
|
||||
width: 92rpx;
|
||||
height: 92rpx;
|
||||
margin-bottom: 14rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #f5f7fa;
|
||||
box-shadow: 0 2rpx 8rpx rgba(25, 118, 210, 0.04);
|
||||
transition: box-shadow 0.2s;
|
||||
}
|
||||
.service-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
body {
|
||||
background: #f5f6fa;
|
||||
}
|
||||
</style>
|
||||
@@ -408,7 +408,6 @@ const initMenuConfig = () => {
|
||||
{ text: "dev-第三方应用", icon: "/static/icon/login.png", router: "/pages/thirdApp/happyMall" },
|
||||
{ text: "dev-登录", icon: "/static/icon/login.png", router: "/pages/user/login" },
|
||||
{ text: "dev-角色选择", icon: "/static/icon/login.png", router: "/pages/user/userRole" },
|
||||
{ text: "dev-意见反馈", icon: "/static/icon/service_5.png", router: "/pages/integrated/feedback/index" },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
File renamed without changes.
File renamed without changes.
Reference in new issue
Block a user