feat: 新增排班管理页面
This commit is contained in:
parent
6fcb1a828b
commit
3be6d0bf9b
@ -123,6 +123,14 @@ export const getStoreDetail = (id) => get('/store/get', { id })
|
|||||||
// 更新店铺
|
// 更新店铺
|
||||||
export const updateStore = (data) => put('/store/update', data)
|
export const updateStore = (data) => put('/store/update', data)
|
||||||
|
|
||||||
|
// 门店日程(某日预约 + 手动占用)
|
||||||
|
export const getScheduleDay = (storeId, date) => get('/schedule/day', { storeId, date })
|
||||||
|
|
||||||
|
/** blockType: walk_in | blocked;slotStart: ISO 本地时间 */
|
||||||
|
export const createScheduleBlock = (data) => post('/schedule/block', data)
|
||||||
|
|
||||||
|
export const deleteScheduleBlock = (id) => del(`/schedule/block?id=${id}`)
|
||||||
|
|
||||||
// 上传图片(uniapp 版:使用 uni.uploadFile)
|
// 上传图片(uniapp 版:使用 uni.uploadFile)
|
||||||
export const uploadImage = (filePath) =>
|
export const uploadImage = (filePath) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
|
|||||||
@ -40,6 +40,12 @@ const ICON_MAP = {
|
|||||||
pin: [
|
pin: [
|
||||||
'M15 10.5a3 3 0 11-6 0 3 3 0 016 0z',
|
'M15 10.5a3 3 0 11-6 0 3 3 0 016 0z',
|
||||||
'M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25S4.5 17.642 4.5 10.5a7.5 7.5 0 1115 0z'
|
'M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25S4.5 17.642 4.5 10.5a7.5 7.5 0 1115 0z'
|
||||||
|
],
|
||||||
|
calendar: [
|
||||||
|
'M7.5 4H16.5C17.33 4 18 4.67 18 5.5V18.5C18 19.33 17.33 20 16.5 20H7.5C6.67 20 6 19.33 6 18.5V5.5C6 4.67 6.67 4 7.5 4Z',
|
||||||
|
'M8 2.5V5',
|
||||||
|
'M16 2.5V5',
|
||||||
|
'M6 9H18'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
{"path": "pages/mine/Staff"},
|
{"path": "pages/mine/Staff"},
|
||||||
{"path": "pages/mine/ServiceType"},
|
{"path": "pages/mine/ServiceType"},
|
||||||
{"path": "pages/mine/Store"},
|
{"path": "pages/mine/Store"},
|
||||||
|
{"path": "pages/mine/Schedule"},
|
||||||
{"path": "pages/mine/MyReports"},
|
{"path": "pages/mine/MyReports"},
|
||||||
{"path": "pages/mine/MyOrders"},
|
{"path": "pages/mine/MyOrders"},
|
||||||
{"path": "pages/mine/MyPets"},
|
{"path": "pages/mine/MyPets"},
|
||||||
|
|||||||
@ -34,6 +34,11 @@
|
|||||||
<text class="menu-text">店铺设置</text>
|
<text class="menu-text">店铺设置</text>
|
||||||
<text class="menu-arrow">›</text>
|
<text class="menu-arrow">›</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="menu-item" @click="goSchedulePage">
|
||||||
|
<view class="menu-icon-wrap"><AppIcon name="calendar" :size="16" color="#666660" /></view>
|
||||||
|
<text class="menu-text">门店日程</text>
|
||||||
|
<text class="menu-arrow">›</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@ -46,6 +51,11 @@
|
|||||||
<text class="menu-text">店铺设置</text>
|
<text class="menu-text">店铺设置</text>
|
||||||
<text class="menu-arrow">›</text>
|
<text class="menu-arrow">›</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="menu-item" @click="goSchedulePage">
|
||||||
|
<view class="menu-icon-wrap"><AppIcon name="calendar" :size="16" color="#666660" /></view>
|
||||||
|
<text class="menu-text">门店日程</text>
|
||||||
|
<text class="menu-arrow">›</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@ -91,6 +101,7 @@ const { goPage, openAppPage } = useNavigator()
|
|||||||
const goStaffPage = () => uni.navigateTo({ url: '/pages/mine/Staff' })
|
const goStaffPage = () => uni.navigateTo({ url: '/pages/mine/Staff' })
|
||||||
const goServiceTypePage = () => uni.navigateTo({ url: '/pages/mine/ServiceType' })
|
const goServiceTypePage = () => uni.navigateTo({ url: '/pages/mine/ServiceType' })
|
||||||
const goStorePage = () => uni.navigateTo({ url: '/pages/mine/Store' })
|
const goStorePage = () => uni.navigateTo({ url: '/pages/mine/Store' })
|
||||||
|
const goSchedulePage = () => uni.navigateTo({ url: '/pages/mine/Schedule' })
|
||||||
const openProfile = () => uni.navigateTo({ url: '/pages/mine/Profile' })
|
const openProfile = () => uni.navigateTo({ url: '/pages/mine/Profile' })
|
||||||
const goMyPetsPage = () => uni.navigateTo({ url: '/pages/mine/MyPets' })
|
const goMyPetsPage = () => uni.navigateTo({ url: '/pages/mine/MyPets' })
|
||||||
const goMyOrdersPage = () => uni.navigateTo({ url: '/pages/mine/MyOrders' })
|
const goMyOrdersPage = () => uni.navigateTo({ url: '/pages/mine/MyOrders' })
|
||||||
|
|||||||
450
src/pages/mine/Schedule.vue
Normal file
450
src/pages/mine/Schedule.vue
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
<template>
|
||||||
|
<view class="page-shell sched-page">
|
||||||
|
<view class="sched-nav nav-gradient" :style="navSafeStyle">
|
||||||
|
<view class="nav-back" @click="goBack"><AppIcon name="back" :size="18" color="#ffffff" /></view>
|
||||||
|
<text class="nav-title">门店日程</text>
|
||||||
|
<view class="nav-placeholder"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="!allowed" class="sched-deny">
|
||||||
|
<text class="sched-deny-text">仅店长与员工可查看门店日程</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-else class="sched-body">
|
||||||
|
<view class="sched-hero">
|
||||||
|
<view class="sched-hero-icon" aria-hidden="true">
|
||||||
|
<AppIcon name="calendar" :size="22" color="#15803d" />
|
||||||
|
</view>
|
||||||
|
<view class="sched-hero-text">
|
||||||
|
<text class="sched-hero-title">时段一览</text>
|
||||||
|
<text class="sched-hero-desc">绿色为客户预约;橙色为到店占用;灰色为暂停线上预约。点空白格可手动占用,点占用可取消。</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="sched-date-bar">
|
||||||
|
<view class="sched-date-btn" @click="shiftDay(-1)">‹</view>
|
||||||
|
<picker mode="date" :value="dateStr" @change="onDatePick">
|
||||||
|
<view class="sched-date-mid">
|
||||||
|
<text class="sched-date-label">{{ dateStr }}</text>
|
||||||
|
<text class="sched-date-sub">{{ weekdayText }}</text>
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
<view class="sched-date-btn" @click="shiftDay(1)">›</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="loading" class="sched-loading"><text>加载中…</text></view>
|
||||||
|
|
||||||
|
<view v-else class="sched-list">
|
||||||
|
<view
|
||||||
|
v-for="(row, idx) in rows"
|
||||||
|
:key="idx"
|
||||||
|
:class="['sched-row', rowRowClass(row)]"
|
||||||
|
@click="onRowTap(row)"
|
||||||
|
>
|
||||||
|
<view class="sched-time-col">
|
||||||
|
<text class="sched-time">{{ row.time }}</text>
|
||||||
|
<text class="sched-range">{{ slotRangeLabel(row) }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="sched-main">
|
||||||
|
<template v-if="row.kind === 'appointment' && row.appointment">
|
||||||
|
<text class="sched-line-title">{{ row.appointment.petName || '宠物' }} · {{ row.appointment.serviceType || '服务' }}</text>
|
||||||
|
<text class="sched-line-sub">{{ apptStatusText(row.appointment.status) }}</text>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="row.kind === 'block' && row.block">
|
||||||
|
<text class="sched-line-title">{{ blockTitle(row.block) }}</text>
|
||||||
|
<text v-if="row.block.note" class="sched-line-sub">{{ row.block.note }}</text>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<text :class="['sched-empty', row.past ? 'sched-empty--past' : '']">{{ row.past ? '已过去' : '空闲 · 点击占用' }}</text>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="sched-foot-hint">与「营业时间」一致,每半小时一档;占用后客户端该档不可再约。</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted } from 'vue'
|
||||||
|
import AppIcon from '../../components/AppIcon.vue'
|
||||||
|
import { getScheduleDay, createScheduleBlock, deleteScheduleBlock } from '../../api/index.js'
|
||||||
|
import { getStoreSession, getUserSession } from '../../utils/session.js'
|
||||||
|
import { formatHalfHourSlotRange } from '../../utils/halfHourTime.js'
|
||||||
|
import { getAppointmentStatusText } from '../../utils/appointment.js'
|
||||||
|
|
||||||
|
const userInfo = getUserSession()
|
||||||
|
const storeInfo = getStoreSession()
|
||||||
|
|
||||||
|
const allowed = computed(() => userInfo.role === 'boss' || userInfo.role === 'staff')
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const dateStr = ref(todayYmd())
|
||||||
|
const rows = ref([])
|
||||||
|
const meta = ref({ dayStart: '', lastSlotStart: '' })
|
||||||
|
|
||||||
|
const navSafeStyle = (() => {
|
||||||
|
const statusBarHeight = uni.getSystemInfoSync?.().statusBarHeight || 20
|
||||||
|
let navHeight = statusBarHeight + 44
|
||||||
|
const menuRect = uni.getMenuButtonBoundingClientRect?.()
|
||||||
|
if (menuRect && menuRect.top && menuRect.height) {
|
||||||
|
const verticalGap = Math.max(menuRect.top - statusBarHeight, 4)
|
||||||
|
navHeight = statusBarHeight + verticalGap * 2 + menuRect.height
|
||||||
|
}
|
||||||
|
return `padding-top:${statusBarHeight}px;height:${navHeight}px;`
|
||||||
|
})()
|
||||||
|
|
||||||
|
const weekdayText = computed(() => {
|
||||||
|
const [y, m, d] = dateStr.value.split('-').map(Number)
|
||||||
|
const dt = new Date(y, m - 1, d)
|
||||||
|
const w = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][dt.getDay()]
|
||||||
|
return w
|
||||||
|
})
|
||||||
|
|
||||||
|
function todayYmd() {
|
||||||
|
const t = new Date()
|
||||||
|
const y = t.getFullYear()
|
||||||
|
const m = String(t.getMonth() + 1).padStart(2, '0')
|
||||||
|
const d = String(t.getDate()).padStart(2, '0')
|
||||||
|
return `${y}-${m}-${d}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function addDaysYmd(ymd, delta) {
|
||||||
|
const [y, m, d] = ymd.split('-').map(Number)
|
||||||
|
const dt = new Date(y, m - 1, d + delta)
|
||||||
|
const yy = dt.getFullYear()
|
||||||
|
const mm = String(dt.getMonth() + 1).padStart(2, '0')
|
||||||
|
const dd = String(dt.getDate()).padStart(2, '0')
|
||||||
|
return `${yy}-${mm}-${dd}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function goBack() {
|
||||||
|
const pages = getCurrentPages()
|
||||||
|
if (pages.length > 1) uni.navigateBack()
|
||||||
|
else uni.switchTab({ url: '/pages/mine/Mine' })
|
||||||
|
}
|
||||||
|
|
||||||
|
function apptStatusText(s) {
|
||||||
|
return getAppointmentStatusText(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
function blockTitle(block) {
|
||||||
|
if (block.blockType === 'blocked') return '暂停线上预约'
|
||||||
|
return '到店占用'
|
||||||
|
}
|
||||||
|
|
||||||
|
function slotRangeLabel(row) {
|
||||||
|
return formatHalfHourSlotRange(row.time)
|
||||||
|
}
|
||||||
|
|
||||||
|
function rowRowClass(row) {
|
||||||
|
if (row.kind === 'appointment') return 'sched-row--appt'
|
||||||
|
if (row.kind === 'block') {
|
||||||
|
return row.block && row.block.blockType === 'blocked' ? 'sched-row--blocked' : 'sched-row--walkin'
|
||||||
|
}
|
||||||
|
return 'sched-row--empty'
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadDay() {
|
||||||
|
if (!allowed.value || !storeInfo.id) return
|
||||||
|
loading.value = true
|
||||||
|
const res = await getScheduleDay(storeInfo.id, dateStr.value)
|
||||||
|
loading.value = false
|
||||||
|
if (res.code === 200 && res.data) {
|
||||||
|
rows.value = res.data.rows || []
|
||||||
|
meta.value = {
|
||||||
|
dayStart: res.data.dayStart || '',
|
||||||
|
lastSlotStart: res.data.lastSlotStart || ''
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rows.value = []
|
||||||
|
uni.showToast({ title: res.message || '加载失败', icon: 'none' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function shiftDay(delta) {
|
||||||
|
dateStr.value = addDaysYmd(dateStr.value, delta)
|
||||||
|
loadDay()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDatePick(e) {
|
||||||
|
const v = e.detail.value
|
||||||
|
if (v) {
|
||||||
|
dateStr.value = v
|
||||||
|
loadDay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRowTap(row) {
|
||||||
|
if (row.kind === 'appointment' && row.appointment && row.appointment.id) {
|
||||||
|
uni.navigateTo({ url: `/pages/appointment/AppointmentDetail?id=${row.appointment.id}` })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (row.kind === 'block' && row.block && row.block.id) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '取消占用',
|
||||||
|
content: `确定取消「${blockTitle(row.block)}」${formatHalfHourSlotRange(row.time)} 吗?`,
|
||||||
|
success: async (r) => {
|
||||||
|
if (!r.confirm) return
|
||||||
|
const res = await deleteScheduleBlock(row.block.id)
|
||||||
|
if (res.code === 200) {
|
||||||
|
uni.showToast({ title: '已取消', icon: 'success' })
|
||||||
|
loadDay()
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: res.message || '操作失败', icon: 'none' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (row.kind === 'empty') {
|
||||||
|
if (row.past) {
|
||||||
|
uni.showToast({ title: '已过去的时段无法占用', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.showActionSheet({
|
||||||
|
itemList: ['到店占用(未走线上预约)', '暂停线上预约(外出等)'],
|
||||||
|
success: async ({ tapIndex }) => {
|
||||||
|
const blockType = tapIndex === 0 ? 'walk_in' : 'blocked'
|
||||||
|
const slotStart = slotStartForApi(row)
|
||||||
|
const res = await createScheduleBlock({
|
||||||
|
storeId: storeInfo.id,
|
||||||
|
slotStart,
|
||||||
|
blockType,
|
||||||
|
note: '',
|
||||||
|
createdByUserId: userInfo.id
|
||||||
|
})
|
||||||
|
if (res.code === 200) {
|
||||||
|
uni.showToast({ title: '已占用', icon: 'success' })
|
||||||
|
loadDay()
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: res.message || '失败', icon: 'none' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 与后端 LocalDateTime 对齐,无 Z 后缀 */
|
||||||
|
function slotStartForApi(row) {
|
||||||
|
const s = row.slotStart
|
||||||
|
if (s && typeof s === 'string') {
|
||||||
|
return s.length >= 19 ? s.slice(0, 19) : s
|
||||||
|
}
|
||||||
|
return `${dateStr.value}T${row.time}:00`
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (!allowed.value) return
|
||||||
|
if (!storeInfo.id) {
|
||||||
|
uni.showToast({ title: '缺少门店信息,请重新登录', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loadDay()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.sched-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--pet-bg, #f5f7fb);
|
||||||
|
padding-bottom: 48px;
|
||||||
|
}
|
||||||
|
.nav-placeholder {
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
.sched-nav {
|
||||||
|
padding: 14px 16px 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.nav-back {
|
||||||
|
font-size: 20px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.nav-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sched-deny {
|
||||||
|
padding: 48px 24px;
|
||||||
|
}
|
||||||
|
.sched-deny-text {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #666660;
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sched-body {
|
||||||
|
padding: 12px 14px 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sched-hero {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 16px 14px;
|
||||||
|
border-radius: 16px;
|
||||||
|
background: linear-gradient(135deg, #ffffff 0%, #ecfdf3 55%, #f0fdf4 100%);
|
||||||
|
border: 1px solid #d8f0e2;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
.sched-hero-icon {
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
border: 1px solid #bbf7d0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.sched-hero-title {
|
||||||
|
display: block;
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #14532d;
|
||||||
|
}
|
||||||
|
.sched-hero-desc {
|
||||||
|
display: block;
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.55;
|
||||||
|
color: #4b5563;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sched-date-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 14px;
|
||||||
|
border: 1px solid #e6ecf4;
|
||||||
|
padding: 8px 4px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.sched-date-btn {
|
||||||
|
width: 44px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #2db96d;
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
.sched-date-mid {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
padding: 6px 0;
|
||||||
|
}
|
||||||
|
.sched-date-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
.sched-date-sub {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #94a3b8;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sched-loading {
|
||||||
|
padding: 32px;
|
||||||
|
text-align: center;
|
||||||
|
color: #94a3b8;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sched-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.sched-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 14px;
|
||||||
|
border: 1px solid #e6ecf4;
|
||||||
|
padding: 12px 14px;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.sched-row--appt {
|
||||||
|
border-color: #bbf7d0;
|
||||||
|
background: #f7fdf9;
|
||||||
|
}
|
||||||
|
.sched-row--walkin {
|
||||||
|
border-color: #fed7aa;
|
||||||
|
background: #fffbeb;
|
||||||
|
}
|
||||||
|
.sched-row--blocked {
|
||||||
|
border-color: #e2e8f0;
|
||||||
|
background: #f8fafc;
|
||||||
|
}
|
||||||
|
.sched-row--empty {
|
||||||
|
opacity: 0.98;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sched-time-col {
|
||||||
|
width: 72px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.sched-time {
|
||||||
|
display: block;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
.sched-range {
|
||||||
|
display: block;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #94a3b8;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sched-main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.sched-line-title {
|
||||||
|
display: block;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
.sched-line-sub {
|
||||||
|
display: block;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #64748b;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
.sched-empty {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #2db96d;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.sched-empty--past {
|
||||||
|
color: #cbd5e1;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sched-foot-hint {
|
||||||
|
margin-top: 16px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #94a3b8;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -13,7 +13,8 @@ const SUB_ROUTE_MAP = {
|
|||||||
profile: '/pages/mine/Profile',
|
profile: '/pages/mine/Profile',
|
||||||
myReports: '/pages/mine/MyReports',
|
myReports: '/pages/mine/MyReports',
|
||||||
myOrders: '/pages/mine/MyOrders',
|
myOrders: '/pages/mine/MyOrders',
|
||||||
myPets: '/pages/mine/MyPets'
|
myPets: '/pages/mine/MyPets',
|
||||||
|
schedule: '/pages/mine/Schedule'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user