Merge branch 'master' of https://codeup.aliyun.com/bsdtec/biz-mobile-react-cloud
This commit is contained in:
commit
e1895d2bfa
12 files changed
+21874
-51
No files matched your search
@@ -19,13 +19,15 @@ VITE_OAUTH2_APP_CLIENT='mini:mini'
|
||||
# --------------------------- 开发环境 api地址 ----------------------------------
|
||||
# VITE_APP_DEV_SERVICE = https://stgl.pj.gov.cn/api # 域名线上
|
||||
#VITE_APP_DEV_SERVICE = http://59.202.170.152:81/api # 信创线上
|
||||
VITE_APP_DEV_SERVICE = http://192.168.101.125:9999 # 邓-本地
|
||||
#VITE_APP_DEV_SERVICE = http://192.168.101.125:9999 # 邓-本地
|
||||
VITE_APP_DEV_SERVICE = http://127.0.0.1:9999 # 邓-本地
|
||||
# VITE_APP_DEV_SERVICE = http://123.156.230.15:8089/api # 测试线上
|
||||
|
||||
# --------------------------- 开发环境 图片访问基础地址 ---------------------------
|
||||
# VITE_IMAGE_DEV_PATH = https://stgl.pj.gov.cn/api # 域名线上
|
||||
#VITE_IMAGE_DEV_PATH = http://59.202.170.152:81/api # 信创线上
|
||||
VITE_IMAGE_DEV_PATH = http://192.168.101.125:9999 # 邓-本地
|
||||
; VITE_IMAGE_DEV_PATH = http://192.168.101.125:9999 # 邓-本地
|
||||
VITE_IMAGE_DEV_PATH = http://127.0.0.1:9999
|
||||
# VITE_IMAGE_DEV_PATH = http://123.156.230.15:8089/api # 测试线上
|
||||
|
||||
# --------------------------- 生产环境 api地址 ----------------------------------
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
|
||||
// launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
|
||||
"version": "0.0",
|
||||
"configurations": [{
|
||||
"default" :
|
||||
{
|
||||
"launchtype" : "local"
|
||||
},
|
||||
"mp-weixin" :
|
||||
{
|
||||
"launchtype" : "local"
|
||||
},
|
||||
"type" : "uniCloud"
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
+20954
File diff suppressed because it is too large.
Load diff
@@ -81,6 +81,7 @@
|
||||
"@types/node": "^18.0.0",
|
||||
"@vue/runtime-core": "^3.3.11",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
"less": "^4.3.0",
|
||||
"sass": "1.71.1",
|
||||
"sass-loader": "10.0.5",
|
||||
"typescript": "^4.9.4",
|
||||
|
||||
+32
-49
@@ -423,10 +423,34 @@
|
||||
"root": "pages/integrated",
|
||||
"pages": [
|
||||
{
|
||||
"path": "feedback",
|
||||
"path": "index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "综合服务"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "lostAndFound/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "失物招领"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "meeting/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "会议预定"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "feedback/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "意见反馈"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "meeting/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "预约会议"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -500,54 +524,13 @@
|
||||
"iconPath": "",
|
||||
"selectedIconPath": ""
|
||||
}
|
||||
// {
|
||||
// "pagePath": "pages/tabbar/canteen",
|
||||
// "text": "食堂",
|
||||
// "iconPath": "static/tabbar/canteen.png",
|
||||
// "selectedIconPath": "static/tabbar/canteen-select.png"
|
||||
// },
|
||||
// {
|
||||
// "pagePath": "pages/tabbar/selfMerchant",
|
||||
// "text": "自营商家",
|
||||
// "iconPath": "static/tabbar/selfMerchant.png",
|
||||
// "selectedIconPath": "static/tabbar/selfMerchant-select.png"
|
||||
// },
|
||||
// {
|
||||
// pagePath: "pages/tabbar/coopMerchant",
|
||||
// text: "合作商家",
|
||||
// iconPath: "static/tabbar/coopMerchant.png",
|
||||
// selectedIconPath: "static/tabbar/coopMerchant-select.png",
|
||||
// },
|
||||
// {
|
||||
// pagePath: "pages/tabbar/cabinet",
|
||||
// text: "智能柜",
|
||||
// iconPath: "static/tabbar/coopMerchant.png",
|
||||
// selectedIconPath: "static/tabbar/coopMerchant-select.png",
|
||||
// },
|
||||
// {
|
||||
// "pagePath": "pages/tabbar/order",
|
||||
// "text": "订单",
|
||||
// "iconPath": "static/tabbar/order.png",
|
||||
// "selectedIconPath": "static/tabbar/order-select.png"
|
||||
// },
|
||||
// {
|
||||
// "pagePath": "pages/tabbar/flowStatistics",
|
||||
// "text": "流水统计",
|
||||
// "iconPath": "static/tabbar/order.png",
|
||||
// "selectedIconPath": "static/tabbar/order-select.png"
|
||||
// },
|
||||
// {
|
||||
// "pagePath": "pages/tabbar/individualOrder",
|
||||
// "text": "订单",
|
||||
// "iconPath": "static/tabbar/order.png",
|
||||
// "selectedIconPath": "static/tabbar/order-select.png"
|
||||
// },
|
||||
// {
|
||||
// "pagePath": "pages/tabbar/my",
|
||||
// "text": "我的",
|
||||
// "iconPath": "static/tabbar/my.png",
|
||||
// "selectedIconPath": "static/tabbar/my-select.png"
|
||||
// },
|
||||
// ,
|
||||
// {
|
||||
// "pagePath": "pages/integrated/index",
|
||||
// "text": "综合服务",
|
||||
// "iconPath": "static/tabbar/integrated.png",
|
||||
// "selectedIconPath": "static/tabbar/integrated-select.png"
|
||||
// }
|
||||
]
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const services = [
|
||||
{
|
||||
name: 'water-query',
|
||||
label: '会议预定',
|
||||
icon: '/static/service/water-query.png',
|
||||
url: '/pages/integrated/meeting/index'
|
||||
},
|
||||
{
|
||||
name: 'lost-and-found',
|
||||
label: '失物招领',
|
||||
icon: '/static/service/lost-and-found.png',
|
||||
url: '/pages/integrated/lostAndFound/index'
|
||||
}
|
||||
]
|
||||
|
||||
function goPage(item) {
|
||||
if (item.url) {
|
||||
uni.navigateTo({ url: item.url })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.service-container {
|
||||
padding: 24rpx 0;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
.service-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
padding: 0 24rpx;
|
||||
}
|
||||
.service-item {
|
||||
width: 25%;
|
||||
margin-bottom: 32rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.service-icon {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.service-label {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,233 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="custom-nav">
|
||||
<view class="nav-back" @tap="goBack">
|
||||
<text class="back-arrow">←</text>
|
||||
</view>
|
||||
<view class="nav-title">失物招领</view>
|
||||
</view>
|
||||
<scroll-view
|
||||
scroll-y
|
||||
class="scroll-view"
|
||||
@scrolltolower="onLoadMore"
|
||||
refresher-enabled
|
||||
:refresher-triggered="refreshing"
|
||||
@refresherrefresh="onRefresh"
|
||||
>
|
||||
<view v-if="list.length > 0">
|
||||
<view
|
||||
v-for="item in list"
|
||||
:key="item.id"
|
||||
class="item-card"
|
||||
>
|
||||
<view class="item-title">{{ item.title }}</view>
|
||||
<view class="item-description" v-html="item.description"></view>
|
||||
<view class="item-info">
|
||||
<text>地点:{{ item.location }}</text>
|
||||
<text>时间:{{ formatDate(item.dateFound) }}</text>
|
||||
</view>
|
||||
<view :class="['status-tag', item.status === '0' ? 'status-pending' : 'status-claimed']">
|
||||
{{ item.status === '0' ? '待认领' : '已认领' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="empty-box">
|
||||
<text class="empty-text">暂无失物招领信息</text>
|
||||
</view>
|
||||
<view v-if="loading" class="loading">加载中...</view>
|
||||
<view v-if="!hasMore && list.length > 0" class="no-more">没有更多了</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import dayjs from 'dayjs'
|
||||
import lostAndFoundApi from '@/sheep/api/lostAndFound'
|
||||
|
||||
interface LostAndFoundItem {
|
||||
id: string
|
||||
title: string
|
||||
picUrl: string | null
|
||||
description: string
|
||||
dateFound: string
|
||||
location: string
|
||||
status: string
|
||||
}
|
||||
|
||||
interface ApiResponse {
|
||||
code: number
|
||||
data: {
|
||||
records: LostAndFoundItem[]
|
||||
pages: number
|
||||
}
|
||||
}
|
||||
|
||||
const list = ref<LostAndFoundItem[]>([])
|
||||
const current = ref(1)
|
||||
const hasMore = ref(true)
|
||||
const loading = ref(false)
|
||||
const refreshing = ref(false)
|
||||
|
||||
const fetchData = async (page: number = 1) => {
|
||||
try {
|
||||
loading.value = true
|
||||
const response = await lostAndFoundApi.getList({
|
||||
current: page,
|
||||
size: 10,
|
||||
}) as unknown as ApiResponse
|
||||
|
||||
if (response.code === 0 && response.data) {
|
||||
if (page === 1) {
|
||||
list.value = response.data.records
|
||||
} else {
|
||||
list.value = [...list.value, ...response.data.records]
|
||||
}
|
||||
hasMore.value = page < response.data.pages
|
||||
current.value = page
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch lost and found items:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
refreshing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const onLoadMore = () => {
|
||||
if (!loading.value && hasMore.value) {
|
||||
fetchData(current.value + 1)
|
||||
}
|
||||
}
|
||||
|
||||
const onRefresh = async () => {
|
||||
refreshing.value = true
|
||||
await fetchData(1)
|
||||
}
|
||||
|
||||
const formatDate = (date: string) => {
|
||||
return dayjs(date).format('YYYY-MM-DD')
|
||||
}
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.custom-nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 88rpx;
|
||||
background-color: #1777FF;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 30rpx;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.nav-back {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.back-arrow {
|
||||
color: #fff;
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
margin-right: 60rpx; // 为了保持标题居中,抵消返回按钮的宽度
|
||||
}
|
||||
|
||||
.scroll-view {
|
||||
height: calc(100vh - 88rpx);
|
||||
margin-top: 88rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.item-card {
|
||||
margin: 12px;
|
||||
padding: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.item-description {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: #e6f7ff;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.status-claimed {
|
||||
background-color: #f6ffed;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.empty-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.loading, .no-more {
|
||||
text-align: center;
|
||||
padding: 12px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,292 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 顶部自定义导航栏 -->
|
||||
<view class="custom-nav">
|
||||
<view class="nav-back" @tap="goBack">
|
||||
<text class="back-arrow">←</text>
|
||||
</view>
|
||||
<view class="nav-title">预约会议</view>
|
||||
</view>
|
||||
|
||||
<!-- 会议室信息 -->
|
||||
<view class="room-info-box">
|
||||
<image :src="room.img" class="room-img" mode="aspectFill"></image>
|
||||
<view class="room-info-main">
|
||||
<view class="room-title">{{ room.name }} <text class="room-capacity">{{ room.capacity }}人</text></view>
|
||||
<view class="room-address"><text>📍</text> {{ room.address }}</view>
|
||||
<view class="room-tags">
|
||||
<text v-for="tag in room.tags" :key="tag" class="room-tag">{{ tag }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 日期切换 -->
|
||||
<view class="date-tabs">
|
||||
<view v-for="(d, i) in dateTabs" :key="i" :class="['date-tab', i === activeDate ? 'active' : '']" @tap="activeDate = i">{{ d }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 时间选择表格 -->
|
||||
<view class="time-table">
|
||||
<view class="time-row" v-for="(row, rowIdx) in timeTable" :key="rowIdx">
|
||||
<view class="time-cell" v-for="(cell, colIdx) in row" :key="colIdx"
|
||||
:class="cell.status"
|
||||
@tap="selectTime(rowIdx, colIdx)"
|
||||
>
|
||||
<text v-if="cell.status === 'booked'">{{ cell.user }}</text>
|
||||
<text v-else-if="cell.status === 'disabled'">🚫</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="time-labels">
|
||||
<text v-for="h in 10" :key="h" class="time-label">{{ 8 + h }}:00</text>
|
||||
</view>
|
||||
|
||||
<!-- 预约信息 -->
|
||||
<view class="reserve-info">
|
||||
<view>会议时间:{{ selectedTimeText }}</view>
|
||||
<view>时长:{{ selectedDuration }}分钟</view>
|
||||
<view>发起人:张三</view>
|
||||
</view>
|
||||
|
||||
<!-- 预约按钮 -->
|
||||
<view class="reserve-btn" @tap="reserveMeeting">发起会议</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
// 假数据,可替换为实际接口
|
||||
const room = ref({
|
||||
name: '一号会议室',
|
||||
capacity: 20,
|
||||
address: '公司总部南水吧台旁',
|
||||
tags: ['电视', '白板', '投影仪'],
|
||||
img: '/static/meeting/room1.jpg',
|
||||
})
|
||||
|
||||
const dateTabs = ['今天', '明天', '后天', '选择日期']
|
||||
const activeDate = ref(0)
|
||||
|
||||
// 时间表格(4行10列,每格15分钟)
|
||||
const timeTable = ref([
|
||||
[
|
||||
{ status: 'disabled' }, { status: 'disabled' }, { status: 'booked', user: '张三' }, { status: 'booked', user: '张三' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }
|
||||
],
|
||||
[
|
||||
{ status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'booked', user: '张三' }, { status: 'booked', user: '张三' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }
|
||||
],
|
||||
[
|
||||
{ status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }
|
||||
],
|
||||
[
|
||||
{ status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }, { status: 'free' }
|
||||
]
|
||||
])
|
||||
|
||||
const selectedTime = ref<{row: number, col: number} | null>(null)
|
||||
const selectedTimeText = computed(() => {
|
||||
if (!selectedTime.value) return '未选择'
|
||||
const start = 8 + selectedTime.value.col * 0.5
|
||||
const end = start + 0.5
|
||||
return `${Math.floor(start)}:${start % 1 === 0 ? '00' : '30'}~${Math.floor(end)}:${end % 1 === 0 ? '00' : '30'}`
|
||||
})
|
||||
const selectedDuration = computed(() => 30)
|
||||
|
||||
function selectTime(row: number, col: number) {
|
||||
const cell = timeTable.value[row][col]
|
||||
if (cell.status === 'free') {
|
||||
selectedTime.value = { row, col }
|
||||
}
|
||||
}
|
||||
|
||||
function reserveMeeting() {
|
||||
if (!selectedTime.value) {
|
||||
uni.showToast({ title: '请选择时间', icon: 'none' })
|
||||
return
|
||||
}
|
||||
uni.showToast({ title: '预约成功', icon: 'success' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background: #f5f6fa;
|
||||
padding-bottom: 32rpx;
|
||||
}
|
||||
.custom-nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 88rpx;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
z-index: 100;
|
||||
}
|
||||
.nav-back {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.back-arrow {
|
||||
color: #333;
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
.nav-title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
color: #222;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
margin-right: 60rpx;
|
||||
}
|
||||
.room-info-box {
|
||||
margin-top: 100rpx;
|
||||
display: flex;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
|
||||
padding: 24rpx;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.room-img {
|
||||
width: 160rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 8rpx;
|
||||
object-fit: cover;
|
||||
background: #eee;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
.room-info-main {
|
||||
flex: 1;
|
||||
}
|
||||
.room-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #222;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
.room-capacity {
|
||||
font-size: 24rpx;
|
||||
color: #888;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
.room-address {
|
||||
font-size: 24rpx;
|
||||
color: #888;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
.room-tags {
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
.room-tag {
|
||||
display: inline-block;
|
||||
background: #f2f6ff;
|
||||
color: #1777FF;
|
||||
font-size: 22rpx;
|
||||
border-radius: 8rpx;
|
||||
padding: 4rpx 16rpx;
|
||||
margin-right: 12rpx;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
.date-tabs {
|
||||
display: flex;
|
||||
margin: 24rpx 24rpx 0 24rpx;
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
.date-tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 18rpx 0;
|
||||
color: #888;
|
||||
font-size: 28rpx;
|
||||
background: #fff;
|
||||
}
|
||||
.date-tab.active {
|
||||
color: #1777FF;
|
||||
background: #e6f0ff;
|
||||
font-weight: 600;
|
||||
}
|
||||
.time-table {
|
||||
margin: 24rpx;
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 16rpx;
|
||||
}
|
||||
.time-row {
|
||||
display: flex;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
.time-cell {
|
||||
flex: 1;
|
||||
height: 48rpx;
|
||||
margin-right: 4rpx;
|
||||
border-radius: 6rpx;
|
||||
background: #e6eaf2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #bbb;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
.time-cell:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
.time-cell.free {
|
||||
background: #4d8fff;
|
||||
color: #fff;
|
||||
}
|
||||
.time-cell.booked {
|
||||
background: #ffb74d;
|
||||
color: #fff;
|
||||
}
|
||||
.time-cell.disabled {
|
||||
background: #f0f0f0;
|
||||
color: #ccc;
|
||||
}
|
||||
.time-cell.selected {
|
||||
border: 2rpx solid #1777FF;
|
||||
}
|
||||
.time-labels {
|
||||
display: flex;
|
||||
margin: 0 24rpx 16rpx 24rpx;
|
||||
}
|
||||
.time-label {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
color: #bbb;
|
||||
font-size: 20rpx;
|
||||
}
|
||||
.reserve-info {
|
||||
margin: 0 24rpx 16rpx 24rpx;
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 16rpx;
|
||||
color: #333;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.reserve-btn {
|
||||
margin: 0 24rpx;
|
||||
background: linear-gradient(90deg, #0094ff, #06be36);
|
||||
color: #fff;
|
||||
font-size: 30rpx;
|
||||
text-align: center;
|
||||
border-radius: 40rpx;
|
||||
padding: 24rpx 0;
|
||||
font-weight: 600;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 顶部自定义导航栏 -->
|
||||
<view class="custom-nav">
|
||||
<view class="nav-back" @tap="goBack">
|
||||
<text class="back-arrow">←</text>
|
||||
</view>
|
||||
<view class="nav-title">预定会议室</view>
|
||||
</view>
|
||||
|
||||
<!-- 日期选择栏(简化版) -->
|
||||
<view class="date-bar">
|
||||
<text class="date-text">{{ todayText }}</text>
|
||||
<text class="date-arrow">▼</text>
|
||||
</view>
|
||||
|
||||
<!-- 会议室列表 -->
|
||||
<view v-for="room in meetingRooms" :key="room.id" class="room-card" @tap="goDetail(room)">
|
||||
<view class="room-info">
|
||||
<view class="room-main">
|
||||
<view class="room-title">
|
||||
{{ room.roomName }} <text class="room-capacity">{{ room.capacity }}人</text>
|
||||
</view>
|
||||
<view class="room-address">
|
||||
<text class="iconfont">📍</text> {{ room.location || '未知地址' }}
|
||||
</view>
|
||||
<view class="room-tags">
|
||||
<text v-for="eq in room.equipmentNames" :key="eq.name" class="room-tag">
|
||||
{{ eq.name }}<span v-if="eq.quantity"> x{{ eq.quantity }}</span>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<image :src="room.picUrl || '/static/meeting/default.jpg'" class="room-img" mode="aspectFill"></image>
|
||||
</view>
|
||||
<!-- 时间条 -->
|
||||
<view class="timeline-bar">
|
||||
<view v-for="(slot, idx) in room.timeline" :key="idx" :class="['timeline-slot', slot]" />
|
||||
</view>
|
||||
<view class="timeline-labels">
|
||||
<text v-for="h in 17" :key="h" class="timeline-label">{{ h + 7 }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import meetingRoomApi from '@/sheep/api/meetingRoom'
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
const todayText = ref('')
|
||||
const meetingRooms = ref<any[]>([])
|
||||
|
||||
onMounted(() => {
|
||||
todayText.value = getTodayText()
|
||||
fetchMeetingRooms()
|
||||
})
|
||||
|
||||
function getTodayText() {
|
||||
const d = new Date()
|
||||
const week = ['日','一','二','三','四','五','六']
|
||||
return `${d.getMonth()+1}月${d.getDate()}日 周${week[d.getDay()]}`
|
||||
}
|
||||
|
||||
function fetchMeetingRooms() {
|
||||
meetingRoomApi.getMeetingRoomList({ current: 1, size: 10 }).then((res: any) => {
|
||||
if (res.code === 0) {
|
||||
meetingRooms.value = res.data.records
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function goDetail(room) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/integrated/meeting/detail?roomId=${room.id}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background: #f5f6fa;
|
||||
padding-bottom: 32rpx;
|
||||
}
|
||||
.custom-nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 88rpx;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
z-index: 100;
|
||||
}
|
||||
.nav-back {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.back-arrow {
|
||||
color: #333;
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
.nav-title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
color: #222;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
margin-right: 60rpx;
|
||||
}
|
||||
.date-bar {
|
||||
margin-top: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding: 0 32rpx;
|
||||
height: 60rpx;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
.date-text {
|
||||
color: #222;
|
||||
font-size: 28rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
.date-arrow {
|
||||
color: #bbb;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.room-card {
|
||||
margin: 24rpx 24rpx 0 24rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
|
||||
padding: 24rpx;
|
||||
}
|
||||
.room-info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.room-main {
|
||||
flex: 1;
|
||||
}
|
||||
.room-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #222;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
.room-capacity {
|
||||
font-size: 24rpx;
|
||||
color: #888;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
.room-address {
|
||||
font-size: 24rpx;
|
||||
color: #888;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
.room-tags {
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
.room-tag {
|
||||
display: inline-block;
|
||||
background: #f2f6ff;
|
||||
color: #1777FF;
|
||||
font-size: 22rpx;
|
||||
border-radius: 8rpx;
|
||||
padding: 4rpx 16rpx;
|
||||
margin-right: 12rpx;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
.room-img {
|
||||
width: 160rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 8rpx;
|
||||
margin-left: 24rpx;
|
||||
object-fit: cover;
|
||||
background: #eee;
|
||||
}
|
||||
.timeline-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin: 16rpx 0 0 0;
|
||||
height: 16rpx;
|
||||
}
|
||||
.timeline-slot {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
margin-right: 2rpx;
|
||||
border-radius: 4rpx;
|
||||
background: #e6eaf2;
|
||||
}
|
||||
.timeline-slot.busy {
|
||||
background: #ffb74d;
|
||||
}
|
||||
.timeline-slot.free {
|
||||
background: #4d8fff;
|
||||
}
|
||||
.timeline-labels {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
.timeline-label {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
color: #bbb;
|
||||
font-size: 20rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,36 @@
|
||||
import request from "@/sheep/utils/request"
|
||||
|
||||
interface LostAndFoundItem {
|
||||
id: string
|
||||
title: string
|
||||
picUrl: string | null
|
||||
description: string
|
||||
dateFound: string
|
||||
location: string
|
||||
status: string
|
||||
}
|
||||
|
||||
interface PageData {
|
||||
records: LostAndFoundItem[]
|
||||
total: number
|
||||
size: number
|
||||
current: number
|
||||
pages: number
|
||||
}
|
||||
|
||||
interface ApiResponse {
|
||||
code: number
|
||||
msg: string | null
|
||||
data: PageData
|
||||
ok: boolean
|
||||
}
|
||||
|
||||
export default {
|
||||
// 获取失物招领列表
|
||||
getList: (params: { current: number; size: number }) =>
|
||||
request({
|
||||
url: "integrated/lostAndFound/app/page",
|
||||
method: "GET",
|
||||
params,
|
||||
}),
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import request from "@/sheep/utils/request"
|
||||
|
||||
export default {
|
||||
/**
|
||||
* 会议室分页列表
|
||||
*/
|
||||
getMeetingRoomList: (params: { current: number; size: number }) =>
|
||||
request({
|
||||
url: "/integrated/meetingRoom/app/page",
|
||||
method: "GET",
|
||||
params,
|
||||
}),
|
||||
}
|
||||
Reference in new issue
Block a user