| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855 |
- <template>
- <view class="container">
- <!-- 吸顶固定层:状态tab + 搜索 + 筛选 -->
- <view class="sticky-header">
- <!-- 顶部 Tab (待接送/服务中...) -->
- <view class="status-tabs">
- <view class="tab-item" v-for="(tab, index) in tabs" :key="index"
- :class="{ active: currentTab === index }" @click="currentTab = index">
- <text>{{ tab }}</text>
- <view class="indicator" v-if="currentTab === index"></view>
- </view>
- </view>
- <!-- 搜索栏 -->
- <view class="search-bar">
- <view class="search-input-box">
- <input class="search-input" v-model="searchContent" placeholder="搜索地址/电话/姓名"
- placeholder-class="ph-style" />
- </view>
- </view>
- <!-- 筛选栏 (支持自定义下拉) -->
- <view class="filter-wrapper">
- <view class="filter-bar">
- <!-- 订单类型下拉视图 -->
- <view class="filter-item" :class="{ 'active': activeDropdown === 1 }" @click="toggleDropdown(1)">
- <text :class="{ 'active-text': activeDropdown === 1 || currentTypeFilterIdx > 0 }">
- {{ currentTypeFilterIdx > 0 ? typeFilterOptions[currentTypeFilterIdx] : '全部类型' }}
- </text>
- <view class="triangle" :class="activeDropdown === 1 ? 'up' : 'down'"></view>
- </view>
- <!-- 服务时间下拉视图 -->
- <view class="filter-item" :class="{ 'active': activeDropdown === 2 }" @click="toggleDropdown(2)">
- <text :class="{ 'active-text': activeDropdown === 2 || hasTimeFilter }">服务时间</text>
- <view class="triangle" :class="activeDropdown === 2 ? 'up' : 'down'"></view>
- </view>
- </view>
- <!-- 下拉内容面板与遮罩 -->
- <view class="dropdown-mask" v-if="activeDropdown !== 0" @click="closeDropdown"></view>
- <view class="dropdown-panel" v-if="activeDropdown === 1">
- <view class="type-option" v-for="(item, index) in typeFilterOptions" :key="index"
- :class="{ 'selected': currentTypeFilterIdx === index }" @click="selectType(index)">
- <text>{{ item }}</text>
- </view>
- </view>
- <view class="dropdown-panel calendar-panel" v-if="activeDropdown === 2">
- <view class="custom-calendar-container">
- <!-- 头部 -->
- <view class="cal-header">
- <text class="cal-nav-btn" @click="prevMonth">‹</text>
- <text class="cal-title">{{ currentMonth }}</text>
- <text class="cal-nav-btn" @click="nextMonth">›</text>
- </view>
- <!-- 星期条 -->
- <view class="cal-weekdays">
- <text v-for="(wk, idx) in weekDays" :key="idx" class="wk-item">{{ wk }}</text>
- </view>
- <!-- 日期网格 -->
- <view class="cal-body">
- <view v-for="(day, idx) in calendarDays" :key="idx" class="cal-day-box"
- :class="day ? getDateClass(day) : ''" @click="day && selectDateItem(day)">
- <view class="cal-day-text" v-if="day">{{ day }}</view>
- </view>
- </view>
- </view>
- <view class="calendar-actions">
- <button class="cal-btn reset" @click="resetTimeFilter">重置</button>
- <button class="cal-btn confirm" @click="confirmTimeFilter">确定</button>
- </view>
- </view>
- </view><!-- end filter-wrapper -->
- </view><!-- end sticky-header -->
- <!-- 订单列表 -->
- <view class="order-list">
- <view class="order-card" v-for="(item, index) in orderList" :key="index" @click="goToDetail(item)">
- <view class="card-header">
- <view class="type-badge">
- <image class="type-icon" :src="item.typeIcon"></image>
- <text class="type-text">{{ item.typeText }}</text>
- </view>
- <text class="status-badge" :class="getStatusClass(item)">{{ getDisplayStatus(item) }}</text>
- </view>
- <view class="card-body">
- <view class="time-row">
- <view class="time-col">
- <text class="label">{{ item.timeLabel }}:</text>
- <text class="value">{{ item.time }}</text>
- </view>
- <text class="fulfillmentCommission">¥{{ item.fulfillmentCommission }}</text>
- </view>
- <!-- 宠物信息 -->
- <view class="pet-card">
- <image class="pet-avatar" :src="item.petAvatarUrl || item.petAvatar" mode="aspectFill"></image>
- <view class="pet-info">
- <text class="pet-name">{{ item.petName }}</text>
- <text class="pet-breed">品种: {{ item.petBreed }}</text>
- </view>
- </view>
- <!-- 路线信息 (完全复用 Home 样式) -->
- <view class="route-info">
- <template v-if="item.type === 1">
- <view class="route-item" @click.stop="openNavigation(item, 'start')">
- <view class="icon-circle start">起</view>
- <view class="route-line-vertical"></view>
- <view class="address-box">
- <text class="addr-title">{{ item.startLocation }}</text>
- <text class="addr-desc">{{ item.startAddress }}</text>
- </view>
- <image class="nav-arrow" src="/static/icons/nav_arrow.svg"
- style="flex-shrink: 0; align-self: center;"></image>
- </view>
- <view class="route-item" @click.stop="openNavigation(item, 'end')">
- <view class="icon-circle end">终</view>
- <view class="address-box">
- <text class="addr-title">{{ item.endLocation }}</text>
- <text class="addr-desc">{{ item.endAddress }}</text>
- </view>
- <image class="nav-arrow" src="/static/icons/nav_arrow.svg"
- style="flex-shrink: 0; align-self: center;"></image>
- </view>
- </template>
- <template v-else>
- <view class="route-item" @click.stop="openNavigation(item, 'end')">
- <view class="icon-circle service">服</view>
- <view class="address-box">
- <text class="addr-title">{{ item.endLocation }}</text>
- <text class="addr-desc">{{ item.endAddress }}</text>
- </view>
- <image class="nav-arrow" src="/static/icons/nav_arrow.svg"
- style="flex-shrink: 0; align-self: center;"></image>
- </view>
- <view class="service-content" v-if="item.serviceContent">
- <text class="content-label">服务内容:</text>
- <text>{{ item.serviceContent }}</text>
- </view>
- </template>
- </view>
- <!-- 备注 -->
- <view class="remark-box" v-if="item.remark">
- <text>备注:{{ item.remark }}</text>
- </view>
- </view><!-- End of card-body -->
- <!-- 按钮组 -->
- <view class="action-btns" v-if="['接单', '到达', '出发', '开始', '送达', '结束'].includes(item.statusText)">
- <view class="action-left">
- <button class="btn normal" @click.stop="doCall('customer', item)">拨号</button>
- </view>
- <view class="action-right">
- <button class="btn normal danger" v-if="item.status === 2"
- @click.stop="handleCancelOrder(item)">取消</button>
- <button class="btn normal" @click.stop="reportAbnormal(item)">异常上报</button>
- <button class="btn primary" @click.stop="mainAction(item)">到达打卡</button>
- </view>
- </view>
- </view>
- <!-- 已加载完提示文字 -->
- <view class="loading-text">已加载完</view>
- <view style="height: 160rpx;"></view>
- </view>
- <view class="call-mask" v-if="activeCallItem" @click="closeCallMenu"></view>
- </view>
- <!-- 宠物档案弹窗 (复用Home) -->
- <view class="pet-modal-mask" v-if="showPetModal" @click="closePetProfile">
- <view class="pet-modal-content" @click.stop>
- <view class="pet-modal-header">
- <text class="pet-modal-title">宠物档案</text>
- <view class="pm-header-actions">
- <view class="pm-remark-btn" @click="openRemarkInput">备注</view>
- <view class="close-icon-btn" @click="closePetProfile">×</view>
- </view>
- </view>
- <scroll-view scroll-y class="pet-modal-scroll">
- <!-- Basic Info -->
- <view class="pet-base-info">
- <image class="pm-avatar" :src="currentPetInfo.petAvatar" mode="aspectFill"></image>
- <view class="pm-info-text">
- <view class="pm-name-row">
- <text class="pm-name">{{ currentPetInfo.petName }}</text>
- <view class="pm-gender" v-if="currentPetInfo.petGender === 'M'">
- <text class="gender-icon">♂</text>
- <text>公</text>
- </view>
- <view class="pm-gender female" v-else-if="currentPetInfo.petGender === 'F'">
- <text class="gender-icon">♀</text>
- <text>母</text>
- </view>
- </view>
- <text class="pm-breed">品种:{{ currentPetInfo.petBreed }}</text>
- </view>
- </view>
- <!-- Details Grid -->
- <view class="pm-detail-grid">
- <view class="pm-grid-item half">
- <text class="pm-label">年龄</text>
- <text class="pm-val">{{ currentPetInfo.petAge || '未知' }}</text>
- </view>
- <view class="pm-grid-item half">
- <text class="pm-label">体重</text>
- <text class="pm-val">{{ currentPetInfo.petWeight || '未知' }}</text>
- </view>
- <view class="pm-grid-item full">
- <text class="pm-label">性格</text>
- <text class="pm-val">{{ currentPetInfo.petPersonality || '无' }}</text>
- </view>
- <view class="pm-grid-item full">
- <text class="pm-label">爱好</text>
- <text class="pm-val">{{ currentPetInfo.petHobby || '无' }}</text>
- </view>
- <view class="pm-grid-item full">
- <text class="pm-label">备注</text>
- <text class="pm-val">{{ currentPetInfo.petRemark || '无特殊过敏史' }}</text>
- </view>
- </view>
- <!-- Tags -->
- <view class="pm-tags" v-if="currentPetInfo.petTags && currentPetInfo.petTags.length > 0">
- <view class="pm-tag" v-for="(tag, index) in currentPetInfo.petTags" :key="index">{{ tag }}</view>
- </view>
- <!-- Log Section -->
- <view class="pm-section-title">
- <view class="orange-bar"></view>
- <text>备注日志</text>
- </view>
- <view class="pm-log-list">
- <view class="pm-log-item" v-for="(log, lIndex) in currentPetInfo.petLogs" :key="lIndex">
- <text class="pm-log-date">{{ log.date }}</text>
- <text class="pm-log-text">{{ log.content }}</text>
- <text class="pm-log-recorder">{{ log.recorder === '系统记录' ? '' : '记录人: ' }}{{ log.recorder
- }}</text>
- </view>
- </view>
- <view style="height: 30rpx;"></view>
- </scroll-view>
- </view>
- </view>
- <!-- 备注输入弹窗 -->
- <view class="remark-mask" v-if="showRemarkInput" @click="closeRemarkInput">
- <view class="remark-sheet" @click.stop>
- <view class="remark-sheet-header">
- <text class="remark-sheet-title">添加备注</text>
- <view class="close-icon-btn" @click="closeRemarkInput">×</view>
- </view>
- <textarea class="remark-textarea" v-model="remarkText" placeholder="请输入备注内容..." maxlength="500"
- auto-height />
- <view class="remark-submit-btn" @click="submitRemark">提交备注</view>
- </view>
- </view>
- <!-- 选择地图导航弹窗 (复用Home) -->
- <view class="nav-modal-mask" v-if="showNavModal" @click="closeNavModal">
- <view class="nav-action-sheet" @click.stop>
- <view class="nav-sheet-title">选择地图进行导航</view>
- <view class="nav-sheet-item" @click="chooseMap('高德')">高德地图</view>
- <view class="nav-sheet-item" @click="chooseMap('腾讯')">腾讯地图</view>
- <view class="nav-sheet-item" @click="chooseMap('百度')">百度地图</view>
- <view class="nav-sheet-gap"></view>
- <view class="nav-sheet-item cancel" @click="closeNavModal">取消</view>
- </view>
- </view>
- <custom-tabbar currentPath="pages/orders/index"></custom-tabbar>
- </template>
- <script>
- import { getMyOrders, cancelOrderApi } from '@/api/order/subOrder'
- import { listAllService } from '@/api/service/list'
- import { reportGps } from '@/utils/gps'
- import customTabbar from '@/components/custom-tabbar/index.vue'
- export default {
- components: {
- customTabbar
- },
- data() {
- return {
- currentTab: 0,
- tabs: ['待接送/服务', '配送/服务中', '已完成', '已取消'],
- typeFilterOptions: ['全部类型'],
- currentTypeFilterIdx: 0,
- activeDropdown: 0,
- hasTimeFilter: false,
- currentMonth: '',
- viewDate: new Date(),
- weekDays: ['日', '一', '二', '三', '四', '五', '六'],
- calendarDays: [],
- selectedDateRange: [],
- allOrderList: [],
- serviceList: [],
- searchContent: '',
- startServiceTime: '',
- endServiceTime: '',
- showPetModal: false,
- currentPetInfo: {},
- showNavModal: false,
- navTargetItem: null,
- navTargetPointType: '',
- activeCallItem: null,
- showRemarkInput: false,
- remarkText: ''
- }
- },
- created() {
- this.initCalendar();
- },
- async onLoad() {
- await this.loadServiceList()
- await this.loadOrders()
- // 显式请求一次定位授权
- reportGps(true).catch(e => console.log('Init GPS check skipped', e));
- },
- onShow() {
- uni.hideTabBar()
- // 此处不需要重复调用,因为逻辑可能在onLoad已处理,
- // 或者如果需要每次进入都刷新,可以保留,但需确保顺序
- this.loadOrders()
- },
- async onPullDownRefresh() {
- try {
- await this.loadServiceList()
- await this.loadOrders()
- } finally {
- uni.stopPullDownRefresh()
- }
- },
- watch: {
- currentTab() {
- this.loadOrders()
- },
- currentTypeFilterIdx() {
- this.loadOrders()
- },
- searchContent() {
- // 搜索内容变化时,自动重新加载订单
- this.loadOrders()
- }
- },
- computed: {
- orderList() {
- return this.allOrderList;
- }
- },
- methods: {
- async loadServiceList() {
- try {
- const res = await listAllService()
- this.serviceList = res.data || []
- this.typeFilterOptions = ['全部类型', ...this.serviceList.map(s => s.name)]
- } catch (err) {
- console.error('获取服务类型失败:', err)
- }
- },
- async loadOrders() {
- try {
- const statusMap = { 0: 2, 1: 3, 2: 4, 3: 5 }
- const serviceId = this.currentTypeFilterIdx > 0 ? this.serviceList[this.currentTypeFilterIdx - 1]?.id : undefined
- const params = {
- status: statusMap[this.currentTab],
- content: this.searchContent || undefined,
- service: serviceId,
- startServiceTime: this.startServiceTime || undefined,
- endServiceTime: this.endServiceTime || undefined
- }
- console.log('订单列表请求参数:', params)
- const res = await getMyOrders(params)
- console.log('订单列表响应:', res)
- const orders = res.rows || []
- console.log('订单数量:', orders.length)
- this.allOrderList = orders.map(order => this.transformOrder(order, this.currentTab))
- } catch (err) {
- console.error('获取订单列表失败:', err)
- this.allOrderList = []
- }
- },
- transformOrder(order, tabIndex) {
- const service = this.serviceList.find(s => s.id === order.service)
- const serviceText = service?.name || '未知'
- const serviceIcon = service?.iconUrl || ''
- const mode = service?.mode || 0
- const isRoundTrip = mode === 1
- // 根据 Tab 索引强制指定状态文字,忽略后端缺失的 status 字段
- let statusText = '接单'
- if (tabIndex === 0) {
- statusText = '接单' // 待接送/服务
- } else if (tabIndex === 1) {
- statusText = isRoundTrip ? '出发' : '开始' // 配送/服务中
- } else if (tabIndex === 2) {
- statusText = '已完成' // 已完成
- } else if (tabIndex === 3) {
- statusText = '已拒绝' // 已拒绝
- }
- return {
- id: order.id,
- status: order.status, // 保存原始 status 用于判断权限
- type: isRoundTrip ? 1 : 2,
- typeText: serviceText,
- typeIcon: serviceIcon,
- statusText: statusText,
- fulfillmentCommission: (order.price / 100).toFixed(2),
- timeLabel: '服务时间',
- time: order.serviceTime || '',
- petAvatar: order.petAvatar || '/static/dog.png',
- petAvatarUrl: order.petAvatarUrl || '',
- petName: order.petName || '',
- petBreed: order.breed || '',
- startLocation: order.fromAddress || '暂无起点',
- startAddress: order.fromAddress || '',
- fromAddress: order.fromAddress || '',
- fromLat: order.fromLat,
- fromLng: order.fromLng,
- startDistance: '0km',
- endLocation: (order.customerName || '') + ' ' + (order.customerPhone || ''),
- endAddress: order.toAddress || '',
- toAddress: order.toAddress || '',
- toLat: order.toLat,
- toLng: order.toLng,
- customerPhone: order.customerPhone || '',
- endDistance: '0km',
- serviceContent: order.remark || '',
- remark: order.remark || ''
- }
- },
- getDisplayStatus(item) {
- if (item.statusText === '已完成') return '已完成';
- if (item.statusText === '已拒绝') return '已拒绝';
- if (item.statusText === '接单') {
- return item.type === 1 ? '待接送' : '待服务';
- }
- return item.type === 1 ? '配送中' : '服务中';
- },
- getStatusClass(item) {
- let display = this.getDisplayStatus(item);
- if (display === '已完成') return 'finish';
- if (display === '已拒绝') return 'reject';
- if (display === '配送中' || display === '服务中') return 'processing';
- return 'highlight';
- },
- goToDetail(item) {
- uni.navigateTo({ url: `/pages/orders/detail/index?id=${item.id}` });
- },
- showPetProfile(item) {
- this.currentPetInfo = {
- ...item,
- petGender: 'M',
- petAge: '2岁',
- petWeight: '15kg',
- petPersonality: '活泼亲人,精力旺盛',
- petHobby: '喜欢追飞盘,爱吃肉干',
- petRemark: '肠胃较弱,不能乱喂零食;出门易爆冲,请拉紧牵引绳。',
- petTags: ['拉响警报', '不能吃鸡肉', '精力旺盛'],
- petLogs: [
- { date: '2026-02-09 14:00', content: '今天遛弯拉了两次粑粑,精神状态很好。', recorder: '王阿姨' },
- { date: '2026-02-08 10:30', content: '有些挑食,剩了小半碗狗粮。', recorder: '李师傅' },
- { date: '2026-02-05 09:00', content: '建档。', recorder: '系统记录' }
- ]
- };
- this.showPetModal = true;
- },
- closePetProfile() {
- this.showPetModal = false;
- },
- openNavigation(item, pointType) {
- this.navTargetItem = item;
- this.navTargetPointType = pointType;
- this.showNavModal = true;
- },
- closeNavModal() {
- this.showNavModal = false;
- },
- chooseMap(mapType) {
- let item = this.navTargetItem;
- let pointType = this.navTargetPointType;
- // 起 -> fromAddress ; 终 -> toAddress
- let name = pointType === 'start' ? (item.fromAddress || '起点') : (item.toAddress || '终点');
- let address = pointType === 'start' ? (item.fromAddress || '起点地址') : (item.toAddress || '终点地址');
- let latitude = pointType === 'start' ? Number(item.fromLat) : Number(item.toLat);
- let longitude = pointType === 'start' ? Number(item.fromLng) : Number(item.toLng);
- this.showNavModal = false;
- // 统一定义打开地图的函数
- const navigateTo = (lat, lng, addrName, addrDesc) => {
- uni.openLocation({
- latitude: lat,
- longitude: lng,
- name: addrName,
- address: addrDesc || '无法获取详细地址',
- success: function () {
- console.log('打开导航成功: ' + mapType);
- },
- fail: function (err) {
- console.error('打开导航失败:', err);
- uni.showToast({ title: '打开地图失败', icon: 'none' });
- }
- });
- };
- // 如果有目标经纬度,直接打开
- if (latitude && longitude && !isNaN(latitude) && !isNaN(longitude)) {
- navigateTo(latitude, longitude, name, address);
- } else {
- // 如果没有经纬度,按照需求:使用自己当前的经纬度,然后搜索 fromAddress 或者 toAddress
- uni.showLoading({ title: '获取当前位置...', mask: true });
- reportGps(true).then(res => {
- uni.hideLoading();
- // 使用用户当前经纬度作为锚点打开地图,展示目标地址信息
- navigateTo(res.latitude, res.longitude, name, address);
- }).catch(err => {
- uni.hideLoading();
- console.error('获取地理位置失败:', err);
- // 具体的授权引导已在 reportGps 内部处理
- });
- }
- },
- toggleCallMenu(item) {
- if (this.activeCallItem === item) {
- this.activeCallItem = null;
- } else {
- this.activeCallItem = item;
- }
- },
- closeCallMenu() {
- this.activeCallItem = null;
- },
- doCall(type, item) {
- let phoneNum = '';
- const targetItem = item || this.activeCallItem;
- // 1. 获取电话号码
- if (type === 'merchant') {
- phoneNum = '18900008451';
- } else if (type === 'customer') {
- phoneNum = targetItem?.customerPhone;
- }
- // 2. 基础校验
- if (!phoneNum) {
- uni.showToast({ title: '未找到电话号码', icon: 'none' });
- this.activeCallItem = null;
- return;
- }
- // 3. 清洗号码 (去除空格、横杠等非数字字符)
- phoneNum = phoneNum.replace(/[^\d]/g, '');
- // 二次校验:确保清洗后仍有数字
- if (phoneNum.length < 3) {
- uni.showToast({ title: '电话号码格式错误', icon: 'none' });
- this.activeCallItem = null;
- return;
- }
- console.log('正在发起直接呼叫:', phoneNum);
- // 4. 核心逻辑:区分环境处理
- // #ifdef APP-PLUS
- // App 端:使用 uni.makePhoneCall 直接发起呼叫
- uni.makePhoneCall({
- phoneNumber: phoneNum,
- success: () => {
- console.log('成功唤起系统拨号盘');
- },
- fail: (err) => {
- console.error('拨号失败:', err);
- // 常见错误:Permission denied (权限被拒) 或 Activity not found
- let msg = '拨号失败';
- if (err.message && err.message.includes('permission')) {
- msg = '请在手机设置中允许"电话"权限';
- }
- uni.showToast({ title: msg, icon: 'none', duration: 3000 });
- // 如果失败,尝试引导用户去设置页 (仅限 Android)
- // #ifdef APP-ANDROID
- if (err.message && err.message.includes('permission')) {
- uni.showModal({
- title: '权限提示',
- content: '拨打电话需要电话权限,是否前往设置开启?',
- success: (res) => {
- if (res.confirm) {
- plus.runtime.openURL("app-settings:");
- }
- }
- });
- }
- // #endif
- },
- complete: () => {
- this.activeCallItem = null; // 关闭弹窗
- }
- });
- // #endif
- // #ifdef H5
- // H5 端:使用 tel: 协议
- window.location.href = `tel:${phoneNum}`;
- this.activeCallItem = null;
- // #endif
- // #ifdef MP-WEIXIN
- // 小程序端:直接调用 makePhoneCall (微信小程序支持直接弹框确认拨打)
- uni.makePhoneCall({
- phoneNumber: phoneNum,
- fail: () => {
- uni.showToast({ title: '拨号失败', icon: 'none' });
- },
- complete: () => {
- this.activeCallItem = null;
- }
- });
- // #endif
- },
- reportAbnormal(item) {
- uni.navigateTo({ url: '/pages/orders/anomaly/index?orderId=' + (item.id || '') });
- },
- toggleDropdown(idx) {
- if (this.activeDropdown === idx) {
- this.activeDropdown = 0;
- } else {
- this.activeDropdown = idx;
- }
- },
- closeDropdown() {
- this.activeDropdown = 0;
- },
- selectType(index) {
- this.currentTypeFilterIdx = index;
- this.closeDropdown();
- },
- initCalendar() {
- const year = this.viewDate.getFullYear();
- const month = this.viewDate.getMonth();
- this.currentMonth = `${year}年${month + 1}月`;
- // 获取该月第一天是周几 (0-6)
- const firstDay = new Date(year, month, 1).getDay();
- // 获取该月有多少天
- const daysInMonth = new Date(year, month + 1, 0).getDate();
- let days = [];
- // 填充开头的空白
- for (let i = 0; i < firstDay; i++) {
- days.push(0);
- }
- // 填充真实日期
- for (let i = 1; i <= daysInMonth; i++) {
- days.push(i);
- }
- this.calendarDays = days;
- },
- prevMonth() {
- this.viewDate.setMonth(this.viewDate.getMonth() - 1);
- // 切换月份时强制重新创建 Date 对象以触发 Vue 响应式(如果需要)或者简单调用 init
- this.viewDate = new Date(this.viewDate);
- this.initCalendar();
- },
- nextMonth() {
- this.viewDate.setMonth(this.viewDate.getMonth() + 1);
- this.viewDate = new Date(this.viewDate);
- this.initCalendar();
- },
- selectDateItem(day) {
- if (this.selectedDateRange.length === 2) {
- this.selectedDateRange = [day];
- } else if (this.selectedDateRange.length === 1) {
- let start = this.selectedDateRange[0];
- if (day > start) {
- this.selectedDateRange = [start, day];
- } else if (day < start) {
- this.selectedDateRange = [day, start];
- } else {
- this.selectedDateRange = [];
- }
- } else {
- this.selectedDateRange = [day];
- }
- },
- getDateClass(day) {
- if (!day || this.selectedDateRange.length === 0) return '';
- if (this.selectedDateRange.length === 1) {
- return day === this.selectedDateRange[0] ? 'is-start' : '';
- }
- let start = this.selectedDateRange[0];
- let end = this.selectedDateRange[1];
- if (day === start) return 'is-start';
- if (day === end) return 'is-end';
- if (day > start && day < end) return 'is-between';
- return '';
- },
- resetTimeFilter() {
- this.hasTimeFilter = false;
- this.selectedDateRange = [];
- this.startServiceTime = '';
- this.endServiceTime = '';
- this.closeDropdown();
- this.loadOrders();
- },
- confirmTimeFilter() {
- if (this.selectedDateRange.length === 0) {
- uni.showToast({ title: '请先选择日期', icon: 'none' });
- return;
- }
- // 构建时间范围参数
- const year = this.currentMonth.replace(/[^0-9]/g, '').substring(0, 4);
- const month = this.currentMonth.replace(/[^0-9]/g, '').substring(4);
- const pad = (n) => String(n).padStart(2, '0');
- if (this.selectedDateRange.length === 2) {
- this.startServiceTime = `${year}-${pad(month)}-${pad(this.selectedDateRange[0])} 00:00:00`;
- this.endServiceTime = `${year}-${pad(month)}-${pad(this.selectedDateRange[1])} 23:59:59`;
- } else {
- this.startServiceTime = `${year}-${pad(month)}-${pad(this.selectedDateRange[0])} 00:00:00`;
- this.endServiceTime = `${year}-${pad(month)}-${pad(this.selectedDateRange[0])} 23:59:59`;
- }
- this.hasTimeFilter = true;
- this.closeDropdown();
- this.loadOrders();
- },
- getMainActionText(item) {
- return '查看详情';
- },
- mainAction(item) {
- uni.navigateTo({ url: `/pages/orders/detail/index?id=${item.id}` });
- },
- openRemarkInput() {
- this.remarkText = '';
- this.showRemarkInput = true;
- },
- closeRemarkInput() {
- this.showRemarkInput = false;
- this.remarkText = '';
- },
- submitRemark() {
- const text = this.remarkText.trim();
- if (!text) {
- uni.showToast({ title: '备注内容不能为空', icon: 'none' });
- return;
- }
- const now = new Date();
- const dateStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
- if (!this.currentPetInfo.petLogs) {
- this.$set(this.currentPetInfo, 'petLogs', []);
- }
- this.currentPetInfo.petLogs.unshift({
- date: dateStr,
- content: text,
- recorder: '我'
- });
- uni.showToast({ title: '备注已添加', icon: 'success' });
- this.closeRemarkInput();
- },
- /**
- * 取消订单处理逻辑
- * @param {Object} item - 订单项
- */
- handleCancelOrder(item) {
- uni.showModal({
- title: '提示',
- content: '确认是否取消这个订单?',
- success: async (res) => {
- if (res.confirm) {
- try {
- uni.showLoading({ title: '取消中...', mask: true });
- await cancelOrderApi({ orderId: item.id });
- uni.showToast({ title: '订单已取消', icon: 'success' });
- // 延时刷新列表,防止提示框闪现
- setTimeout(() => {
- this.loadOrders();
- }, 1500);
- } catch (err) {
- console.error('取消订单失败:', err);
- uni.showToast({ title: '取消失败', icon: 'none' });
- } finally {
- uni.hideLoading();
- }
- }
- }
- });
- }
- }
- }
- </script>
- <style>
- page {
- background-color: #F8F8F8;
- }
- .custom-nav-bar {
- padding: 80rpx 30rpx 20rpx;
- background-color: #fff;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .nav-title {
- font-size: 34rpx;
- font-weight: bold;
- color: #333;
- }
- .sticky-header {
- position: sticky;
- top: 0;
- z-index: 999;
- background-color: #F8F8F8;
- }
- .container {
- background-color: #F8F8F8;
- display: flex;
- flex-direction: column;
- min-height: 100vh;
- }
- .status-tabs {
- display: flex;
- background-color: #fff;
- padding: 0 30rpx;
- justify-content: space-between;
- }
- .tab-item {
- position: relative;
- padding: 20rpx 0;
- font-size: 26rpx;
- color: #666;
- font-weight: 500;
- }
- .tab-item.active {
- color: #FF5722;
- font-weight: bold;
- }
- .indicator {
- position: absolute;
- bottom: 0;
- left: 50%;
- transform: translateX(-50%);
- width: 40rpx;
- height: 6rpx;
- background-color: #FF5722;
- border-radius: 3rpx;
- }
- .search-bar {
- padding: 10rpx 30rpx;
- background-color: #fff;
- }
- .search-input-box {
- display: flex;
- align-items: center;
- background-color: #F8F8F8;
- height: 64rpx;
- border-radius: 32rpx;
- padding: 0 30rpx;
- }
- .search-input {
- flex: 1;
- font-size: 26rpx;
- color: #333;
- padding-left: 20rpx;
- }
- .ph-style {
- font-size: 26rpx;
- color: #999;
- }
- .filter-wrapper {
- position: relative;
- z-index: 998;
- }
- .filter-bar {
- display: flex;
- background-color: #fff;
- padding: 5rpx 30rpx 10rpx 30rpx;
- justify-content: space-between;
- position: relative;
- z-index: 998;
- }
- .filter-item {
- width: 48%;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 26rpx;
- color: #666;
- background-color: #F8F8F8;
- height: 56rpx;
- border-radius: 12rpx;
- transition: all 0.2s;
- }
- .filter-item.active {
- background-color: #FFF3E0;
- }
- .active-text {
- color: #FF5722;
- font-weight: 500;
- }
- .triangle {
- width: 0;
- height: 0;
- border-left: 8rpx solid transparent;
- border-right: 8rpx solid transparent;
- margin-left: 10rpx;
- transition: all 0.2s;
- }
- .triangle.down {
- border-top: 10rpx solid #dcdcdc;
- }
- .filter-item.active .triangle.down,
- .active-text+.triangle.down {
- border-top-color: #FF5722;
- }
- .triangle.up {
- border-bottom: 10rpx solid #FF5722;
- }
- .dropdown-mask {
- position: absolute;
- top: 100%;
- left: 0;
- right: 0;
- height: 100vh;
- background-color: rgba(0, 0, 0, 0.4);
- z-index: 80;
- }
- .dropdown-panel {
- position: absolute;
- top: 100%;
- left: 0;
- right: 0;
- background-color: #fff;
- z-index: 90;
- border-radius: 0 0 20rpx 20rpx;
- box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.05);
- overflow: hidden;
- }
- .type-option {
- padding: 30rpx 40rpx;
- font-size: 28rpx;
- color: #333;
- border-bottom: 1px solid #f5f5f5;
- }
- .type-option:last-child {
- border-bottom: none;
- }
- .type-option.selected text {
- color: #FF5722;
- font-weight: bold;
- }
- .calendar-panel {
- padding-bottom: 30rpx;
- }
- .custom-calendar-container {
- padding: 20rpx 30rpx 0;
- }
- .cal-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 20rpx 0;
- }
- .cal-title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- }
- .cal-weekdays {
- display: flex;
- justify-content: space-around;
- padding: 20rpx 0;
- border-bottom: 1px solid #f5f5f5;
- }
- .wk-item {
- font-size: 24rpx;
- color: #999;
- width: 14.28%;
- text-align: center;
- }
- .cal-body {
- display: flex;
- flex-wrap: wrap;
- padding-top: 20rpx;
- }
- .cal-day-box {
- width: 14.28%;
- height: 80rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- margin-bottom: 10rpx;
- position: relative;
- }
- .cal-day-text {
- width: 64rpx;
- height: 64rpx;
- line-height: 64rpx;
- text-align: center;
- font-size: 28rpx;
- color: #333;
- border-radius: 8rpx;
- position: relative;
- z-index: 2;
- }
- .cal-day-box.is-start .cal-day-text,
- .cal-day-box.is-end .cal-day-text {
- background-color: #FF5722;
- color: #fff;
- font-weight: bold;
- }
- .cal-day-box.is-start::after {
- content: '';
- position: absolute;
- right: 0;
- top: 8rpx;
- bottom: 8rpx;
- width: 50%;
- background-color: #FFF3E0;
- z-index: 1;
- }
- .cal-day-box.is-end::after {
- content: '';
- position: absolute;
- left: 0;
- top: 8rpx;
- bottom: 8rpx;
- width: 50%;
- background-color: #FFF3E0;
- z-index: 1;
- }
- .cal-day-box.is-start.is-end::after {
- display: none;
- }
- .cal-day-box.is-between {
- background-color: #FFF3E0;
- margin-top: 8rpx;
- height: 64rpx;
- margin-bottom: 18rpx;
- }
- .cal-day-box.is-between .cal-day-text {
- color: #FF5722;
- }
- .calendar-actions {
- display: flex;
- justify-content: space-between;
- padding: 0 30rpx;
- margin-top: 20rpx;
- }
- .cal-btn {
- width: 48%;
- height: 70rpx;
- line-height: 70rpx;
- text-align: center;
- border-radius: 10rpx;
- font-size: 28rpx;
- margin: 0;
- }
- .cal-btn.reset {
- background-color: #f5f5f5;
- color: #666;
- }
- .cal-btn.confirm {
- background-color: #FF5722;
- color: #fff;
- }
- .order-list {
- padding: 0 30rpx;
- width: 100%;
- box-sizing: border-box;
- }
- .order-card {
- background-color: #fff;
- border-radius: 24rpx;
- padding: 20rpx 20rpx;
- margin-bottom: 20rpx;
- box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03);
- }
- .order-card:first-child {
- margin-top: 20rpx;
- }
- .card-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 15rpx;
- }
- .type-badge {
- display: flex;
- align-items: center;
- }
- .type-icon {
- width: 44rpx;
- height: 44rpx;
- margin-right: 15rpx;
- background-color: #FFF3E0;
- border-radius: 50%;
- padding: 6rpx;
- box-sizing: border-box;
- }
- .type-text {
- font-size: 30rpx;
- font-weight: bold;
- color: #333;
- }
- .status-badge {
- font-size: 28rpx;
- }
- .status-badge.highlight {
- color: #FF5722;
- }
- .status-badge.processing {
- color: #2196F3;
- }
- .status-badge.finish {
- color: #4CAF50;
- }
- .status-badge.reject {
- color: #9E9E9E;
- }
- .time-row {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 25rpx;
- }
- .time-row .time-col {
- display: flex;
- align-items: center;
- font-size: 26rpx;
- color: #333;
- }
- .time-row .label {
- color: #666;
- margin-right: 10rpx;
- }
- .fulfillmentCommission {
- font-size: 36rpx;
- font-weight: bold;
- color: #FF5722;
- }
- .pet-card {
- background-color: #FFF8F0;
- border-radius: 16rpx;
- padding: 15rpx 20rpx;
- display: flex;
- align-items: center;
- margin-bottom: 20rpx;
- }
- .pet-avatar {
- width: 80rpx;
- height: 80rpx;
- border-radius: 50%;
- margin-right: 20rpx;
- }
- .pet-info {
- flex: 1;
- display: flex;
- flex-direction: column;
- }
- .pet-name {
- font-size: 28rpx;
- font-weight: bold;
- color: #333;
- margin-bottom: 5rpx;
- }
- .pet-breed {
- font-size: 24rpx;
- color: #999;
- }
- .pet-profile-btn {
- font-size: 24rpx;
- color: #FF9800;
- border: 1px solid #FF9800;
- padding: 6rpx 20rpx;
- border-radius: 50rpx;
- background-color: #fff;
- }
- .route-info {
- margin-bottom: 25rpx;
- }
- .route-item {
- display: flex;
- align-items: flex-start;
- padding-bottom: 12rpx;
- position: relative;
- width: 100%;
- }
- .route-item:not(:last-child) {
- margin-bottom: 5rpx;
- }
- .route-item:last-child {
- padding-bottom: 0;
- margin-bottom: 0;
- }
- .route-line-vertical {
- position: absolute;
- left: 19rpx;
- top: 46rpx;
- bottom: -15rpx;
- border-left: 2rpx dashed #E0E0E0;
- width: 0;
- z-index: 0;
- }
- .icon-circle {
- width: 40rpx;
- height: 40rpx;
- border-radius: 50%;
- color: #fff;
- font-size: 22rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- margin-right: 20rpx;
- flex-shrink: 0;
- font-weight: bold;
- margin-top: 6rpx;
- position: relative;
- z-index: 1;
- }
- .icon-circle.service {
- background-color: #81C784;
- }
- .icon-circle.start {
- background-color: #FFB74D;
- }
- .icon-circle.end {
- background-color: #81C784;
- }
- .address-box {
- flex: 1;
- display: flex;
- flex-direction: column;
- margin-right: 20rpx;
- }
- .addr-title {
- font-size: 28rpx;
- font-weight: bold;
- color: #333;
- margin-bottom: 4rpx;
- }
- .addr-desc {
- font-size: 24rpx;
- color: #999;
- line-height: 1.4;
- }
- .distance-tag {
- display: flex;
- align-items: center;
- justify-content: flex-end;
- flex-shrink: 0;
- min-width: 80rpx;
- }
- .distance-text {
- font-size: 24rpx;
- color: #FF5722;
- margin-right: 15rpx;
- font-weight: 500;
- }
- .nav-icon-circle {
- width: 48rpx;
- height: 48rpx;
- background-color: #FFF3E0;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .nav-arrow {
- width: 24rpx;
- height: 24rpx;
- }
- .service-content {
- margin-top: -10rpx;
- font-size: 24rpx;
- color: #666;
- padding-left: 60rpx;
- }
- .content-label {
- color: #999;
- margin-right: 10rpx;
- }
- .remark-box {
- background-color: #F8F8F8;
- padding: 15rpx 20rpx;
- border-radius: 8rpx;
- font-size: 26rpx;
- color: #666;
- margin-bottom: 30rpx;
- }
- .action-btns {
- display: flex;
- justify-content: space-between;
- margin-top: 15rpx;
- }
- .action-left {
- display: flex;
- }
- .action-right {
- display: flex;
- }
- .btn {
- height: 60rpx;
- line-height: 60rpx;
- border-radius: 30rpx;
- font-size: 26rpx;
- padding: 0 30rpx;
- margin: 0;
- }
- .action-right .btn:not(:last-child) {
- margin-right: 20rpx;
- }
- .btn::after {
- border: none;
- }
- .btn.normal {
- background-color: #F8F8F8;
- color: #666;
- border: none;
- }
- .btn.primary {
- background: linear-gradient(90deg, #FF9800 0%, #FF5722 100%);
- color: #fff;
- box-shadow: 0 4rpx 12rpx rgba(255, 87, 34, 0.2);
- border: none;
- }
- .btn.normal.danger {
- background-color: #FFF2F0;
- color: #F5222D;
- }
- .pet-modal-mask {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.4);
- z-index: 1000;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .pet-modal-content {
- width: 680rpx;
- height: 85vh;
- background-color: #fff;
- border-radius: 20rpx;
- display: flex;
- flex-direction: column;
- overflow: hidden;
- }
- .pet-modal-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 30rpx;
- border-bottom: 1rpx solid #F0F0F0;
- }
- .pet-modal-title {
- font-size: 34rpx;
- font-weight: bold;
- color: #333;
- }
- .pet-modal-scroll {
- flex: 1;
- height: 0;
- padding: 30rpx;
- box-sizing: border-box;
- }
- .pet-base-info {
- display: flex;
- align-items: center;
- margin-bottom: 40rpx;
- }
- .pm-avatar {
- width: 120rpx;
- height: 120rpx;
- border-radius: 50%;
- margin-right: 30rpx;
- border: 2rpx solid #f5f5f5;
- }
- .pm-info-text {
- flex: 1;
- display: flex;
- flex-direction: column;
- }
- .pm-name-row {
- display: flex;
- align-items: center;
- margin-bottom: 15rpx;
- }
- .pm-name {
- font-size: 36rpx;
- font-weight: bold;
- color: #333;
- margin-right: 20rpx;
- }
- .pm-gender {
- display: flex;
- align-items: center;
- background-color: #E3F2FD;
- padding: 4rpx 12rpx;
- border-radius: 20rpx;
- }
- .pm-gender text {
- font-size: 22rpx;
- color: #1E88E5;
- }
- .pm-gender .gender-icon {
- font-weight: bold;
- margin-right: 4rpx;
- }
- .pm-gender.female {
- background-color: #FCE4EC;
- }
- .pm-gender.female text {
- color: #D81B60;
- }
- .pm-breed {
- font-size: 26rpx;
- color: #999;
- }
- .pm-detail-grid {
- display: flex;
- flex-wrap: wrap;
- justify-content: space-between;
- }
- .pm-grid-item {
- background-color: #F8F8F8;
- border-radius: 16rpx;
- padding: 24rpx;
- margin-bottom: 20rpx;
- display: flex;
- flex-direction: column;
- }
- .pm-grid-item.half {
- width: 48%;
- box-sizing: border-box;
- }
- .pm-grid-item.full {
- width: 100%;
- box-sizing: border-box;
- }
- .pm-label {
- font-size: 24rpx;
- color: #999;
- margin-bottom: 10rpx;
- }
- .pm-val {
- font-size: 28rpx;
- color: #333;
- font-weight: 500;
- }
- .pm-tags {
- display: flex;
- flex-wrap: wrap;
- gap: 20rpx;
- margin-bottom: 40rpx;
- }
- .pm-tag {
- background-color: #FFF8EB;
- border: 2rpx solid #FFCC80;
- color: #FF9800;
- font-size: 22rpx;
- padding: 8rpx 24rpx;
- border-radius: 30rpx;
- }
- .pm-section-title {
- display: flex;
- align-items: center;
- margin-bottom: 30rpx;
- padding-top: 30rpx;
- border-top: 2rpx dashed #F0F0F0;
- }
- .pm-section-title .orange-bar {
- width: 8rpx;
- height: 32rpx;
- background-color: #FF9800;
- margin-right: 16rpx;
- border-radius: 4rpx;
- }
- .pm-section-title text {
- font-size: 30rpx;
- font-weight: bold;
- color: #333;
- }
- .pm-log-list {
- display: flex;
- flex-direction: column;
- }
- .pm-log-item {
- display: flex;
- flex-direction: column;
- padding: 24rpx 0;
- border-bottom: 1rpx solid #F0F0F0;
- }
- .pm-log-item:last-child {
- border-bottom: none;
- }
- .pm-log-date {
- font-size: 24rpx;
- color: #999;
- margin-bottom: 16rpx;
- }
- .pm-log-text {
- font-size: 28rpx;
- color: #333;
- line-height: 1.6;
- margin-bottom: 20rpx;
- }
- .pm-log-recorder {
- font-size: 24rpx;
- color: #FF9800;
- align-self: flex-end;
- }
- .pm-bottom-close {
- width: 100%;
- height: 80rpx;
- line-height: 80rpx;
- background-color: #F5F5F5;
- color: #666;
- border-radius: 40rpx;
- font-size: 30rpx;
- font-weight: bold;
- margin: 0;
- }
- .pm-bottom-close::after {
- border: none;
- }
- .close-icon-btn {
- font-size: 48rpx;
- color: #999;
- line-height: 1;
- padding: 0 10rpx;
- }
- .nav-modal-mask {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.5);
- z-index: 1000;
- display: flex;
- flex-direction: column;
- justify-content: flex-end;
- }
- .nav-action-sheet {
- background-color: #fff;
- width: 100%;
- border-top-left-radius: 24rpx;
- border-top-right-radius: 24rpx;
- overflow: hidden;
- padding-bottom: constant(safe-area-inset-bottom);
- padding-bottom: env(safe-area-inset-bottom);
- }
- .nav-sheet-title {
- text-align: center;
- padding: 30rpx 0;
- font-size: 13px;
- color: #999;
- border-bottom: 1rpx solid #efefef;
- }
- .nav-sheet-item {
- text-align: center;
- padding: 30rpx 0;
- font-size: 13px;
- color: #333;
- background-color: #fff;
- border-bottom: 1rpx solid #efefef;
- }
- .nav-sheet-item.cancel {
- border-bottom: none;
- color: #666;
- }
- .nav-sheet-gap {
- height: 16rpx;
- background-color: #F8F8F8;
- }
- .order-list {
- flex: 1;
- overflow-y: auto;
- width: 100%;
- padding: 0 30rpx;
- box-sizing: border-box;
- }
- .loading-text {
- text-align: center;
- font-size: 24rpx;
- color: #999;
- padding: 30rpx 0;
- }
- .pm-header-actions {
- display: flex;
- align-items: center;
- gap: 16rpx;
- }
- .pm-remark-btn {
- font-size: 24rpx;
- color: #fff;
- background-color: #FF9800;
- padding: 6rpx 18rpx;
- border-radius: 20rpx;
- }
- .remark-mask {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.5);
- z-index: 3000;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .remark-sheet {
- width: 600rpx;
- background-color: #fff;
- border-radius: 24rpx;
- padding: 40rpx;
- box-sizing: border-box;
- display: flex;
- flex-direction: column;
- align-items: center;
- }
- .remark-sheet-header {
- width: 100%;
- text-align: center;
- margin-bottom: 30rpx;
- position: relative;
- }
- .remark-sheet-header .close-icon-btn {
- position: absolute;
- right: 0;
- top: 50%;
- transform: translateY(-50%);
- }
- .remark-sheet-title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- }
- .remark-textarea {
- width: 100%;
- height: 160rpx;
- border: 1rpx solid #eee;
- border-radius: 12rpx;
- padding: 20rpx;
- font-size: 28rpx;
- color: #333;
- box-sizing: border-box;
- margin-bottom: 40rpx;
- }
- .remark-submit-btn {
- width: 100%;
- background-color: #FF5722;
- color: #fff;
- font-size: 32rpx;
- font-weight: bold;
- text-align: center;
- padding: 24rpx 0;
- border-radius: 16rpx;
- }
- .action-left {
- position: relative;
- z-index: 10;
- }
- .action-left .btn.normal {
- font-size: 26rpx;
- }
- .call-popover {
- position: absolute;
- top: calc(100% + 10rpx);
- left: 0;
- background-color: #fff;
- border-radius: 12rpx;
- box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
- z-index: 999;
- display: flex;
- flex-direction: column;
- width: 200rpx;
- }
- .call-pop-item {
- font-size: 26rpx;
- color: #333;
- text-align: center;
- padding: 24rpx 0;
- border-bottom: 1rpx solid #eee;
- }
- .call-pop-item:last-child {
- border-bottom: none;
- }
- .call-mask {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 900;
- background: transparent;
- }
- </style>
|