| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641 |
- <template>
- <view class="detail-container">
- <!-- 加载动画 -->
- <view class="loading-container" v-if="pageLoading">
- <!-- 顶部骨架 -->
- <view class="skeleton-header">
- <view class="skeleton-line skeleton-ani" style="width: 30%; height: 36rpx;"></view>
- <view class="skeleton-line skeleton-ani" style="width: 20%; height: 36rpx;"></view>
- </view>
- <view class="skeleton-progress">
- <view class="skeleton-circle skeleton-ani" v-for="i in 4" :key="i"></view>
- </view>
- <!-- 卡片骨架 -->
- <view class="skeleton-card" v-for="j in 3" :key="'c' + j">
- <view class="skeleton-line skeleton-ani" style="width: 60%; height: 28rpx; margin-bottom: 20rpx;">
- </view>
- <view class="skeleton-line skeleton-ani" style="width: 90%; height: 24rpx; margin-bottom: 14rpx;">
- </view>
- <view class="skeleton-line skeleton-ani" style="width: 75%; height: 24rpx;"></view>
- </view>
- </view>
- <template v-else>
- <!-- 顶部动态状态区 -->
- <view class="detail-header">
- <view class="status-row">
- <text class="status-title">{{ displayStatusText }}</text>
- <text class="status-price">¥{{ orderDetail.fulfillmentCommission }}</text>
- </view>
- <!-- 进度条区域 -->
- <view class="progress-bar">
- <view class="step-item" v-for="(step, index) in progressSteps" :key="index"
- :class="{ 'active': index === progressIndex, 'done': index < progressIndex }">
- <view class="step-circle-wrapper">
- <!-- Connecting Line before circle, except first item -->
- <view class="step-line" v-if="index !== 0"
- :class="{ 'active-line': index <= progressIndex }">
- </view>
- <view class="step-circle">{{ index + 1 }}</view>
- </view>
- <text class="step-text">{{ step }}</text>
- </view>
- </view>
- </view>
- <!-- 内容区域 -->
- <scroll-view scroll-y class="detail-content">
- <!-- 宠物信息 -->
- <view class="white-card pet-bar">
- <image class="pb-avatar" :src="orderDetail.petAvatar" mode="aspectFill"></image>
- <view class="pb-info">
- <view class="pb-name-row">
- <text class="pb-name">{{ orderDetail.petName }}</text>
- </view>
- <view class="pb-tags">
- <text class="pb-tag">{{ orderDetail.serviceName }}</text>
- </view>
- </view>
- <view class="pb-actions">
- <view class="pb-btn profile-btn" @click="showPetProfile">宠物档案</view>
- <view class="pb-btn phone-btn" @click="callPhone">
- <image class="phone-icon" src="/static/icons/phone_orange.svg"></image>
- </view>
- </view>
- </view>
- <!-- 路线及服务信息 -->
- <view class="white-card service-info-card">
- <view class="si-row time-row">
- <image class="si-icon outline" src="/static/icons/clock.svg"></image>
- <view class="si-content">
- <text class="si-label">服务时间</text>
- <text class="si-val">{{ orderDetail.time }}</text>
- </view>
- <view class="si-action record-btn" @tap.stop="openAnomalyModal">
- <text>异常记录</text>
- <image class="record-arrow" src="/static/icons/right_arrow_orange.svg"></image>
- </view>
- </view>
- <!-- 接送类型的地址展现 -->
- <template v-if="orderDetail.type === 1">
- <view class="si-row addr-row start-addr">
- <view class="icon-circle start">起</view>
- <view class="route-line-vertical"></view>
- <view class="si-content">
- <text class="si-addr-title">{{ orderDetail.startLocation }}</text>
- <text class="si-addr-desc">{{ orderDetail.startAddress }}</text>
- </view>
- <view class="nav-btn-circle" @click="openNavigation('start')">
- <image class="nav-arrow" src="/static/icons/nav_arrow.svg"></image>
- </view>
- </view>
- <view class="si-row addr-row end-addr">
- <view class="icon-circle end">终</view>
- <view class="si-content">
- <text class="si-addr-title">{{ orderDetail.endLocation }}</text>
- <text class="si-addr-desc">{{ orderDetail.endAddress }}</text>
- </view>
- <view class="nav-btn-circle" @click="openNavigation('end')">
- <image class="nav-arrow" src="/static/icons/nav_arrow.svg"></image>
- </view>
- </view>
- </template>
- <!-- 喂遛/洗护类型的地址展现 -->
- <template v-else>
- <view class="si-row addr-row end-addr">
- <view class="icon-circle service">服</view>
- <view class="si-content">
- <text class="si-addr-title">{{ orderDetail.endLocation }}</text>
- <text class="si-addr-desc">{{ orderDetail.endAddress }}</text>
- </view>
- <view class="nav-btn-circle" @click="openNavigation('end')">
- <image class="nav-arrow" src="/static/icons/nav_arrow.svg"></image>
- </view>
- </view>
- </template>
- <view class="si-row">
- <image class="si-icon outline custom-icon-file" src="/static/icons/file.svg"></image>
- <view class="si-content">
- <text class="si-label">备注</text>
- <text class="si-val">{{ orderDetail.remark || '-' }}</text>
- </view>
- </view>
- <!-- <view class="si-row record-history-row" @tap.stop="openAnomalyModal">
- <view class="si-content">
- <text class="si-label">异常记录</text>
- <text class="si-val">查看历史异常记录</text>
- </view>
- <image class="record-arrow" src="/static/icons/right_arrow_orange.svg"></image>
- </view> -->
- </view>
- <!-- 打卡任务 -->
- <view class="white-card task-card" v-if="currentStep < steps.length">
- <text class="tc-title">当前任务:{{ currentTaskTitle }}</text>
- <text class="tc-desc">{{ currentTaskDesc }}</text>
- <!-- 单个巨大点击区触发弹窗 -->
- <view class="full-media-add" @click="openUploadModal">
- <image class="upload-icon-large" src="/static/icons/camera_grey.svg"></image>
- <text class="upload-text-large">上传图或视频</text>
- </view>
- </view>
- <!-- 订单属性 -->
- <view class="white-card base-info-card">
- <view class="bi-row">
- <image class="si-icon outline" src="/static/icons/order_no.svg"></image>
- <view class="bi-content">
- <text class="bi-label">订单编号</text>
- <view class="bi-val-row">
- <text class="bi-val">{{ orderDetail.orderNo }}</text>
- <text class="bi-copy" @click="copyOrderNo">复制</text>
- </view>
- </view>
- </view>
- <view class="bi-row">
- <image class="si-icon outline" src="/static/icons/clock.svg"></image>
- <view class="bi-content">
- <text class="bi-label">下单时间</text>
- <text class="bi-val">{{ orderDetail.createTime }}</text>
- </view>
- </view>
- </view>
- <!-- 订单进度 -->
- <view class="white-card timeline-card">
- <view class="tl-title-row">
- <view class="orange-bar"></view>
- <text class="tl-title">订单进度</text>
- </view>
- <view class="tl-list">
- <view class="tl-item" v-for="(log, idx) in orderDetail.progressLogs" :key="idx">
- <view class="tl-marker active">
- <view class="tl-dot-inner"></view>
- </view>
- <view class="tl-content-row">
- <view class="tl-header">
- <text class="tl-status">{{ log.status }}</text>
- <text class="tl-time">{{ log.time }}</text>
- </view>
- <!-- 媒体(图片/视频)展示 -->
- <view class="tl-medias" v-if="log.medias && log.medias.length > 0">
- <view class="tl-media-item" v-for="(media, midx) in log.medias" :key="midx"
- @click="previewMedia(log.medias, midx)">
- <image v-if="!isVideo(media)" class="tl-img" :src="media" mode="aspectFill">
- </image>
- <view v-else class="tl-video-placeholder">
- <view class="tl-play-icon">
- </view>
- <text class="tl-video-label">视频</text>
- </view>
- </view>
- </view>
- <!-- 备注展示 -->
- <view class="tl-remark" v-if="log.remark">
- <text>{{ log.remark }}</text>
- </view>
- </view>
- </view>
- </view>
- </view>
- <view style="height: 140rpx;"></view>
- </scroll-view>
- <!-- 底部操作栏 -->
- <view class="bottom-action-bar">
- <view class="action-left">
- <button class="action-btn outline grey-outline" @click="goToAnomaly">异常上报</button>
- <button class="action-btn outline orange-outline" @click="openSumModal"
- v-if="serviceMode === 0">宠护小结</button>
- </view>
- <view class="action-right">
- <button class="action-btn primary" @click="openUploadModal" v-if="currentStep < steps.length">{{
- currentTaskTitle }}</button>
- <button class="action-btn primary grey-bg" v-else>已完成</button>
- </view>
- </view>
- <!-- 宠物档案弹窗 -->
- <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 style="flex:1"></view>
- <view class="pm-remark-btn" @click="openPetRemarkInput">备注</view>
- <view class="close-icon-btn" @click="closePetProfile">×</view>
- </view>
- <scroll-view scroll-y class="pet-modal-scroll">
- <!-- 宠物基础信息 -->
- <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>
- <!-- 属性网格 -->
- <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>
- <!-- 标签 -->
- <view class="pm-tags-row" v-if="currentPetInfo.petTags && currentPetInfo.petTags.length > 0">
- <view class="pm-tag-chip" v-for="(tag, ti) in currentPetInfo.petTags" :key="ti">
- <text class="pm-tag-chip-text">{{ tag }}</text>
- </view>
- </view>
- <!-- 备注日志 -->
- <view class="pm-log-section">
- <view class="pm-log-header">
- <view
- style="width:6rpx; height:28rpx; background:#FF9800; border-radius:3rpx; margin-right:12rpx;">
- </view>
- <text class="pm-log-section-title">备注日志</text>
- </view>
- <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" v-if="log.recorder !== '系统记录'">记录人:{{ log.recorder
- }}</text>
- <text class="pm-log-recorder system" v-else>系统记录</text>
- </view>
- </view>
- <view style="height: 30rpx;"></view>
- </scroll-view>
- </view>
- </view>
- <!-- 宠物备注输入弹窗 -->
- <view class="upload-modal-mask" v-if="showPetRemarkInput" @click="closePetRemarkInput">
- <view class="upload-modal-content" @click.stop>
- <view class="um-header">
- <text class="um-title">添加备注</text>
- </view>
- <view class="um-body">
- <textarea class="um-textarea" v-model="petRemarkText" auto-height placeholder="请输入宠物备注内容..."
- placeholder-style="color:#ccc; font-size:26rpx;"></textarea>
- </view>
- <view class="um-footer">
- <button class="um-submit-btn active" @click="submitPetRemark">确认提交</button>
- </view>
- </view>
- </view>
- <!-- 选择地图导航弹窗 (复用) -->
- <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>
- <!-- 上传图视频弹窗 (新增) -->
- <view class="upload-modal-mask" v-if="showUploadModal" @click="closeUploadModal">
- <view class="upload-modal-content" @click.stop>
- <view class="um-header">
- <text class="um-title">上传图或视频 ({{ modalMediaList.length }}/6)</text>
- <text class="um-remark-hint">{{ currentTaskDesc }}</text>
- </view>
- <view class="um-body">
- <view class="um-grid">
- <view class="um-item" v-for="(img, idx) in modalMediaList" :key="idx">
- <image class="um-preview" :src="img.thumb || img.url || img.localPath || img"
- mode="aspectFill">
- </image>
- <view class="um-video-badge" v-if="img.mediaType === 'video'">
- <image class="play-icon-small" src="/static/icons/play_circle.svg"></image>
- </view>
- <view class="um-del" @click="removeModalMedia(idx)">×</view>
- </view>
- <view class="um-add" @click="chooseModalMedia" v-if="modalMediaList.length < 6">
- <image class="um-add-icon" src="/static/icons/camera_grey.svg"></image>
- <text class="um-add-text">拍摄/上传</text>
- </view>
- </view>
- <textarea class="um-textarea" v-model="modalRemark" placeholder="在此输入备注信息..."
- placeholder-style="color:#ccc; font-size:26rpx;"></textarea>
- </view>
- <view class="um-footer">
- <view class="um-submit-btn" :class="{ 'active': modalMediaList.length > 0 }"
- @click="handleConfirmUpload">
- 确认提交</view>
- </view>
- </view>
- </view>
- <!-- 宠护小结弹窗 -->
- <view class="sum-modal-mask" v-if="showSumModal" @click="closeSumModal">
- <view class="sum-modal-card" @click.stop>
- <scroll-view scroll-y class="sum-modal-scroll">
- <view class="sum-modal-inner">
- <text class="sum-modal-title">宠物护理工作小结</text>
- <view class="sum-meta-row">
- <text class="sum-meta-label">日期:</text>
- <text class="sum-meta-val">{{ sumDate }}</text>
- </view>
- <view class="sum-meta-row">
- <text class="sum-meta-label">客户住址:</text>
- <text class="sum-meta-val">{{ orderDetail.endAddress }}</text>
- </view>
- <view class="sum-meta-row">
- <text class="sum-meta-label">宠主姓名:</text>
- <text class="sum-meta-val">{{ orderDetail.ownerName || '未知' }}</text>
- </view>
- <view class="sum-section-title">宠物信息</view>
- <view class="sum-pet-card">
- <image class="sum-pet-avatar" :src="orderDetail.petAvatar" mode="aspectFill"></image>
- <view class="sum-pet-info">
- <view class="sum-pet-name-row">
- <text class="sum-pet-name">{{ orderDetail.petName || '未知' }}</text>
- <text class="sum-pet-breed">品种: {{ orderDetail.petBreed || '未知' }}</text>
- </view>
- <text class="sum-pet-remark">{{ orderDetail.petNotes || '暂无备注' }}</text>
- </view>
- </view>
- <view class="sum-section-title">服务内容记录</view>
- <textarea class="sum-textarea" v-model="sumContent" auto-height placeholder="请填写服务内容..."
- placeholder-style="color:#ccc"></textarea>
- <view class="sum-sign-row">
- <text class="sum-sign-label">护宠师签名:</text>
- <text class="sum-sign-val">{{ sumSigner }}</text>
- </view>
- <view style="height: 20rpx;"></view>
- </view>
- </scroll-view>
- <view class="sum-footer">
- <button class="sum-submit-btn" @click="submitSumModal">提交小结</button>
- </view>
- </view>
- </view>
- <!-- 异常记录弹窗 -->
- <view class="modal-mask" v-if="showAnomalyModal" @click="closeAnomalyModal">
- <view class="anomaly-modal-content" @click.stop>
- <view class="am-header">
- <text class="am-title">历史异常记录</text>
- <view class="close-icon-btn" @click="closeAnomalyModal">×</view>
- </view>
- <scroll-view scroll-y class="am-scroll-list">
- <view class="empty-list" v-if="anomalyList.length === 0">
- <image class="empty-icon" src="/static/empty-rest.png" mode="aspectFit"></image>
- <text class="empty-text">暂无异常记录</text>
- </view>
- <view class="am-item" v-for="(item, index) in anomalyList" :key="index">
- <view class="am-item-header">
- <text class="am-item-type">{{ item.typeLabel }}</text>
- <text class="am-item-status" :class="'status-' + item.status">{{
- getAnomalyStatusLabel(item.status)
- }}</text>
- </view>
- <text class="am-item-content">{{ item.content }}</text>
- <view class="am-item-photos" v-if="item.photos && item.photos.length > 0">
- <view class="am-photo-item" v-for="(photoUrl, pIdx) in item.photoUrls" :key="pIdx"
- @click="previewMedia(item.photoUrls, pIdx)">
- <image v-if="!isVideo(photoUrl)" class="am-photo" :src="photoUrl" mode="aspectFill">
- </image>
- <view v-else class="tl-video-placeholder miniaturized">
- <view class="tl-play-icon small">
- </view>
- <text class="tl-video-label small">视频</text>
- </view>
- </view>
- </view>
- <view class="am-audit-box" v-if="item.status !== 0">
- <view class="am-audit-header">
- <text class="am-audit-label">{{ item.status === 1 ? '审核通过' : '驳回理由' }}</text>
- <text class="am-audit-time">{{ item.auditTime }}</text>
- </view>
- <text class="am-audit-remark">{{ item.auditRemark || '无' }}</text>
- </view>
- </view>
- </scroll-view>
- </view>
- </view>
- <!-- 视频播放弹窗 -->
- <view class="video-player-mask" v-if="videoPlayerShow" @click="closeVideoPlayer">
- <view class="video-player-content" @click.stop>
- <video class="v-player" :src="videoPlayerUrl" autoplay controls></video>
- <view class="v-close" @click="closeVideoPlayer">×</view>
- </view>
- </view>
- </template>
- </view>
- </template>
- <script>
- import { getOrderInfo, clockIn, submitNursingSummary } from '@/api/order/subOrder'
- import { getOrderLogs } from '@/api/order/subOrderLog'
- import { uploadFile } from '@/api/fulfiller/app'
- import { getAnomalyList } from '@/api/fulfiller/anamaly'
- import { listAllService } from '@/api/service/list'
- import { reportGps } from '@/utils/gps'
- import { getDictDataByType } from '@/api/system/dict'
- import { getPetDetail, submitPetRemark as apiSubmitPetRemark } from '@/api/archieves/pet'
- import { listChangeLog } from '@/api/archieves/changeLog'
- export default {
- data() {
- return {
- orderId: null,
- pageLoading: true,
- orderType: 1,
- orderStatus: 2,
- serviceId: null,
- serviceMode: null,
- petId: null,
- petDetail: null,
- clockInSteps: [],
- currentClockIn: null,
- currentStep: 0,
- orderDetail: {
- type: 1, fulfillmentCommission: '0.00', timeLabel: '服务时间', time: '',
- petAvatar: '/static/dog.png', petName: '', petBreed: '',
- serviceTag: '', startLocation: '', startAddress: '', endAddress: '',
- customerPhone: '', serviceContent: '', remark: '',
- orderNo: '', createTime: '', serviceName: '',
- progressLogs: [], nursingSummary: ''
- },
- serviceList: [],
- showPetModal: false,
- currentPetInfo: {},
- showNavModal: false,
- navTargetPointType: '',
- showUploadModal: false,
- modalMediaList: [],
- modalRemark: '',
- showSumModal: false,
- sumContent: '',
- sumDate: '',
- sumSigner: '未知',
- showPetRemarkInput: false,
- petRemarkText: '',
- showAnomalyModal: false,
- anomalyList: [],
- anomalyTypeDict: [],
- videoPlayerShow: false,
- videoPlayerUrl: ''
- }
- },
- computed: {
- steps() {
- if (this.clockInSteps.length > 0) return this.clockInSteps.map(s => s.title)
- return this.orderType === 1
- ? ['到达打卡', '确认出发', '送达打卡']
- : ['到达打卡', '开始服务', '服务结束']
- },
- progressSteps() { return ['已接单', ...this.steps, '订单完成'] },
- progressIndex() { return this.currentStep + 1 },
- displayStatusText() {
- if (this.currentStep >= this.steps.length) return '已完成';
- if (this.currentStep > 0) return this.orderType === 1 ? '配送中' : '服务中';
- return this.orderType === 1 ? '待接送' : '待服务';
- },
- currentStatusText() {
- return this.currentStep >= this.steps.length ? '已完成' : this.steps[this.currentStep];
- },
- currentTaskTitle() {
- if (this.currentStep >= this.steps.length) return '订单已完成';
- if (this.currentClockIn) return this.currentClockIn.title;
- return this.steps[this.currentStep] || '打卡';
- },
- currentTaskDesc() {
- if (this.currentStep >= this.steps.length) return '感谢您的服务,请注意休息';
- if (this.currentClockIn && this.currentClockIn.remark) return this.currentClockIn.remark;
- return '请按要求提交照片或视频及备注';
- }
- },
- async onLoad(options) {
- if (options.id) this.orderId = options.id
- this.pageLoading = true
- reportGps(true).catch(e => console.log('Init GPS check skipped', e));
- try {
- await this.loadAnomalyTypeDict()
- await this.loadServiceList()
- await this.loadOrderDetail()
- } finally {
- this.pageLoading = false
- }
- },
- methods: {
- async loadServiceList() {
- try {
- const res = await listAllService()
- this.serviceList = res.data || []
- } catch (err) { console.error('获取服务类型失败:', err); uni.showToast({ title: err.message || err.msg || '请求失败', icon: 'none' }) }
- },
- loadServiceDetail(serviceId) {
- const serviceInfo = (this.serviceList || []).find(s => s.id === serviceId)
- if (serviceInfo) {
- this.serviceMode = serviceInfo.mode
- this.orderDetail.serviceName = serviceInfo.name
- if (serviceInfo.clockInRemark) {
- try {
- const parsed = JSON.parse(serviceInfo.clockInRemark)
- if (Array.isArray(parsed) && parsed.length > 0) this.clockInSteps = parsed
- } catch (parseErr) { console.error('解析 clockInRemark 失败:', parseErr) }
- }
- }
- },
- async loadOrderDetail() {
- if (!this.orderId) { uni.showToast({ title: '订单ID缺失', icon: 'none' }); return }
- try {
- const res = await getOrderInfo(this.orderId)
- const order = res.data
- if (!order) { uni.showToast({ title: '订单不存在', icon: 'none' }); return }
- this.serviceId = order.service
- this.petId = order.usrPet || null
- this.transformOrderData(order)
- if (this.serviceId) this.loadServiceDetail(this.serviceId)
- if (this.petId) await this.loadPetDetail(this.petId)
- await this.loadOrderLogs()
- } catch (err) {
- console.error('获取订单详情失败:', err)
- uni.showToast({ title: err.message || err.msg || '加载失败', icon: 'none' })
- }
- },
- async loadOrderLogs() {
- try {
- const res = await getOrderLogs(this.orderId)
- const logs = res.data || []
- const progressLogs = logs.filter(log => log.logType === 1)
- this.orderDetail.progressLogs = progressLogs.map(log => ({
- status: log.title || '', time: log.createTime || '',
- medias: log.photoUrls || [], remark: log.content || ''
- }))
- const validLogs = logs.filter(log => log.logType === 1 && log.step !== undefined && log.step !== null)
- .sort((a, b) => new Date(b.createTime).getTime() - new Date(a.createTime).getTime())
- if (validLogs.length > 0) {
- const latestStep = validLogs[0].step
- const stepIndex = this.clockInSteps.findIndex(s => s.step === latestStep)
- this.currentStep = stepIndex >= 0 ? stepIndex + 1 : Number(latestStep)
- } else { this.currentStep = 0 }
- this.updateCurrentClockIn()
- } catch (err) { console.error('获取订单日志失败:', err); uni.showToast({ title: err.message || err.msg || '请求失败', icon: 'none' }) }
- },
- updateCurrentClockIn() {
- this.currentClockIn = this.currentStep < this.clockInSteps.length ? this.clockInSteps[this.currentStep] : null
- },
- transformOrderData(order) {
- const mode = order.mode || 0
- const isRoundTrip = mode === 1
- this.orderType = isRoundTrip ? 1 : 2
- this.orderStatus = order.status || 2
- this.orderDetail = {
- type: this.orderType,
- fulfillmentCommission: (order.fulfillmentCommission / 100).toFixed(2),
- timeLabel: isRoundTrip ? '取货时间' : '服务时间',
- time: order.serviceTime || '',
- petAvatar: '/static/dog.png',
- petName: order.petName || order.contact || '',
- petBreed: order.breed || '',
- serviceTag: order.groupPurchasePackageName || '',
- startLocation: order.fromAddress || '暂无起点',
- startAddress: order.fromAddress || '',
- fromAddress: order.fromAddress || '',
- fromLat: order.fromLat, fromLng: order.fromLng,
- endLocation: (order.contact || '') + ' ' + (order.contactPhoneNumber || ''),
- endAddress: order.toAddress || '',
- toAddress: order.toAddress || '',
- toLat: order.toLat, toLng: order.toLng,
- customerPhone: order.contactPhoneNumber || '',
- ownerName: order.contact || '',
- serviceContent: order.remark || '', remark: order.remark || '',
- orderNo: order.code || 'T' + order.id,
- createTime: order.serviceTime || '',
- nursingSummary: order.nursingSummary || '',
- fulfillerName: order.fulfillerName || '',
- progressLogs: [{ status: '您已接单', time: order.serviceTime || '' }]
- }
- if (this.orderDetail.fulfillerName) this.sumSigner = this.orderDetail.fulfillerName
- },
- async loadPetDetail(petId) {
- try {
- const res = await getPetDetail(petId)
- const pet = res.data
- if (pet) {
- this.petDetail = pet
- this.orderDetail.petAvatar = pet.avatarUrl || '/static/dog.png'
- this.orderDetail.petName = pet.name || this.orderDetail.petName
- this.orderDetail.petBreed = pet.breed || this.orderDetail.petBreed
- this.orderDetail.ownerName = pet.ownerName || this.orderDetail.ownerName
- }
- } catch (err) { console.error('获取宠物档案失败:', err); uni.showToast({ title: err.message || err.msg || '请求失败', icon: 'none' }) }
- },
- async loadAnomalyList() {
- if (!this.orderId) return
- try {
- const res = await getAnomalyList(this.orderId)
- const list = res.data || []
- this.anomalyList = list.map(item => {
- const dict = this.anomalyTypeDict.find(d => d.value === item.type)
- return { ...item, typeLabel: dict ? dict.label : item.type, photoUrls: item.photoUrls || [] }
- })
- } catch (err) { console.error('获取异常列表失败:', err); uni.showToast({ title: err.message || err.msg || '请求失败', icon: 'none' }) }
- },
- async loadAnomalyTypeDict() {
- try {
- const res = await getDictDataByType('flf_anamaly_type')
- this.anomalyTypeDict = res.data.map(item => ({ label: item.dictLabel, value: item.dictValue }))
- } catch (err) { console.error('获取异常字典失败:', err); uni.showToast({ title: err.message || err.msg || '请求失败', icon: 'none' }) }
- },
- openAnomalyModal() { this.showAnomalyModal = true; this.loadAnomalyList() },
- closeAnomalyModal() { this.showAnomalyModal = false },
- getAnomalyStatusLabel(status) {
- return { 0: '待审核', 1: '已通过', 2: '已驳回' }[status] || '未知'
- },
- showPetProfile() {
- const pet = this.petDetail
- if (pet) {
- this.currentPetInfo = {
- petAvatar: pet.avatarUrl || '/static/dog.png',
- petName: pet.name || '', petBreed: pet.breed || '',
- petGender: pet.gender === 1 ? 'M' : (pet.gender === 2 ? 'F' : ''),
- petAge: pet.age ? pet.age + '岁' : '未知',
- petWeight: pet.weight ? pet.weight + 'kg' : '未知',
- petPersonality: pet.personality || pet.cutePersonality || '无',
- petHobby: '', petRemark: pet.remark || '无',
- petTags: (pet.tags || []).map(t => t.name), petLogs: [],
- petSize: pet.size || '', petIsSterilized: pet.isSterilized,
- petHealthStatus: pet.healthStatus || '', petAllergies: pet.allergies || '',
- petMedicalHistory: pet.medicalHistory || '', petVaccineStatus: pet.vaccineStatus || '',
- ownerName: pet.ownerName || '', ownerPhone: pet.ownerPhone || ''
- }
- this.loadPetChangeLogs(pet.id)
- } else {
- this.currentPetInfo = {
- ...this.orderDetail, petGender: '', petAge: '未知', petWeight: '未知',
- petPersonality: '无', petHobby: '', petRemark: '无', petTags: [], petLogs: []
- }
- }
- this.showPetModal = true
- },
- async loadPetChangeLogs(petId) {
- if (!petId) return
- try {
- const res = await listChangeLog({ targetId: petId, targetType: 'pet' })
- const logs = res.data || []
- this.currentPetInfo.petLogs = logs.map(item => ({
- date: item.createTime || '', content: item.content || '', recorder: item.operatorName || '未知'
- }))
- } catch (err) { console.error('获取宠物备注列表失败:', err); uni.showToast({ title: err.message || err.msg || '请求失败', icon: 'none' }) }
- },
- closePetProfile() { this.showPetModal = false },
- openPetRemarkInput() { this.petRemarkText = ''; this.showPetRemarkInput = true },
- closePetRemarkInput() { this.showPetRemarkInput = false },
- async submitPetRemark() {
- if (!this.petRemarkText.trim()) { uni.showToast({ title: '备注内容不能为空', icon: 'none' }); return }
- if (!this.petId) { uni.showToast({ title: '宠物信息缺失', icon: 'none' }); return }
- uni.showLoading({ title: '提交中...', mask: true });
- try {
- await apiSubmitPetRemark({ petId: this.petId, content: this.petRemarkText });
- uni.hideLoading(); uni.showToast({ title: '备注已添加', icon: 'success' });
- this.closePetRemarkInput(); this.loadPetChangeLogs(this.petId);
- } catch (err) { uni.hideLoading(); console.error('提交宠物备注失败:', err); uni.showToast({ title: err.message || err.msg || '请求失败', icon: 'none' }) }
- },
- goToAnomaly() {
- uni.navigateTo({ url: '/pages/orders/anomaly/index?orderId=' + (this.orderId || '') });
- },
- callPhone() {
- const phoneNum = this.orderDetail.customerPhone || '18900008451'
- if (!phoneNum) { uni.showToast({ title: '手机号不存在', icon: 'none' }); return }
- uni.showModal({
- title: '拨号提示',
- content: `系统将为您拨打手机号: ${phoneNum},请授予拨号权限以正常通话。`,
- confirmText: '呼叫', cancelText: '取消',
- success: (res) => {
- if (res.confirm) {
- uni.makePhoneCall({
- phoneNumber: phoneNum,
- fail: () => { uni.showToast({ title: '无法唤起拨号盘,请检查权限设置', icon: 'none' }) }
- });
- }
- }
- });
- },
- openNavigation(type) { this.navTargetPointType = type; this.showNavModal = true },
- closeNavModal() { this.showNavModal = false },
- chooseMap(mapType) {
- let pointType = this.navTargetPointType;
- let name = pointType === 'start' ? (this.orderDetail.fromAddress || '起点') : (this.orderDetail.toAddress || '终点');
- let address = pointType === 'start' ? (this.orderDetail.fromAddress || '起点地址') : (this.orderDetail.toAddress || '终点地址');
- let latitude = pointType === 'start' ? Number(this.orderDetail.fromLat) : Number(this.orderDetail.toLat);
- let longitude = pointType === 'start' ? Number(this.orderDetail.fromLng) : Number(this.orderDetail.toLng);
- this.showNavModal = false;
- const navigateTo = (lat, lng, addrName, addrDesc) => {
- uni.openLocation({
- latitude: lat, longitude: lng, name: addrName,
- address: addrDesc || '无法获取详细地址',
- success: () => { console.log('打开导航成功: ' + mapType) },
- fail: (err) => { console.error('打开导航失败:', err); uni.showToast({ title: '打开地图失败', icon: 'none' }) }
- });
- };
- if (latitude && longitude && !isNaN(latitude) && !isNaN(longitude)) {
- navigateTo(latitude, longitude, name, address);
- } else {
- 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); uni.showToast({ title: err.message || err.msg || '请求失败', icon: 'none' }) });
- }
- },
- openUploadModal() { this.modalMediaList = []; this.modalRemark = ''; this.showUploadModal = true },
- closeUploadModal() { this.showUploadModal = false },
- handleConfirmUpload() { this.confirmUploadModal() },
- chooseModalMedia() {
- uni.showActionSheet({
- itemList: ['选择图片', '选择视频'],
- success: (asRes) => {
- if (asRes.tapIndex === 0) {
- uni.chooseImage({
- count: 6 - this.modalMediaList.length,
- sizeType: ['compressed'],
- sourceType: ['album', 'camera'],
- success: async (res) => {
- uni.showLoading({ title: '上传中...', mask: true });
- try {
- for (const filePath of res.tempFilePaths) {
- const uploadRes = await uploadFile(filePath);
- if (uploadRes.code === 200) {
- this.modalMediaList.push({
- url: uploadRes.data.url, ossId: uploadRes.data.ossId,
- localPath: filePath, mediaType: 'image'
- });
- }
- }
- uni.hideLoading(); uni.showToast({ title: '上传成功', icon: 'success' });
- } catch (err) { uni.hideLoading(); uni.showToast({ title: err.message || err.msg || '上传失败', icon: 'none' }) }
- },
- fail: (err) => { console.error('选择图片失败:', err) }
- });
- } else if (asRes.tapIndex === 1) {
- uni.chooseVideo({
- sourceType: ['album', 'camera'],
- compressed: true,
- success: async (res) => {
- uni.showLoading({ title: '上传中...', mask: true });
- try {
- const uploadRes = await uploadFile(res.tempFilePath);
- if (uploadRes.code === 200) {
- this.modalMediaList.push({
- url: uploadRes.data.url, ossId: uploadRes.data.ossId,
- localPath: res.tempFilePath, mediaType: 'video',
- thumb: res.thumbTempFilePath || res.tempFilePath
- });
- }
- uni.hideLoading(); uni.showToast({ title: '上传成功', icon: 'success' });
- } catch (err) { uni.hideLoading(); uni.showToast({ title: err.message || err.msg || '上传失败', icon: 'none' }) }
- },
- fail: (err) => { console.error('选择视频失败:', err) }
- });
- }
- }
- });
- },
- removeModalMedia(index) { this.modalMediaList.splice(index, 1) },
- async confirmUploadModal() {
- if (this.modalMediaList.length === 0) { uni.showToast({ title: '请上传至少一张图片或视频', icon: 'none' }); return }
- try {
- uni.showLoading({ title: '提交中...' });
- const ossIds = this.modalMediaList.map(item => item.ossId);
- const clockInType = this.currentClockIn ? this.currentClockIn.step : (this.currentStep + 1);
- const clockInData = {
- orderId: this.orderId, photos: ossIds,
- content: this.modalRemark || '', step: clockInType,
- title: this.currentTaskTitle,
- startFlag: Number(clockInType) === 1,
- endFlag: Number(this.currentStep) === this.steps.length - 1
- };
- await clockIn(clockInData);
- uni.hideLoading(); this.closeUploadModal();
- uni.showToast({ title: '打卡成功', icon: 'success' });
- await this.loadOrderDetail();
- } catch (err) {
- uni.hideLoading(); console.error('打卡失败:', err);
- uni.showToast({ title: err.message || err.msg || '打卡失败', icon: 'none' });
- }
- },
- copyOrderNo() {
- uni.setClipboardData({ data: this.orderDetail.orderNo, success: () => { uni.showToast({ title: '复制成功', icon: 'none' }) } });
- },
- openSumModal() {
- let displayDate = '';
- if (this.orderDetail.time) {
- displayDate = this.orderDetail.time.split(' ')[0].replace(/-/g, '/');
- } else {
- const now = new Date();
- displayDate = `${now.getFullYear()}/${String(now.getMonth() + 1).padStart(2, '0')}/${String(now.getDate()).padStart(2, '0')}`;
- }
- this.sumDate = displayDate;
- if (this.orderDetail.nursingSummary) {
- this.sumContent = this.orderDetail.nursingSummary;
- } else if (!this.sumContent) {
- this.sumContent = '1. 精神/身体状态:\n2. 进食/饮水:\n3. 排泤情况:\n4. 卫生情况:\n5. 互动情况:\n6. 特殊情况/备注:';
- }
- this.showSumModal = true;
- },
- closeSumModal() { this.showSumModal = false },
- async submitSumModal() {
- if (!this.sumContent.trim()) { uni.showToast({ title: '请填写服务内容', icon: 'none' }); return }
- uni.showLoading({ title: '提交中...', mask: true });
- try {
- const res = await submitNursingSummary({ orderId: this.orderId, content: this.sumContent });
- uni.hideLoading();
- if (res.code === 200) {
- uni.showToast({ title: '小结已提交', icon: 'success' });
- this.closeSumModal(); await this.loadOrderDetail();
- } else {
- // 对于业务失败,如果 request.js 没弹,这里补一下,但要用原信息
- uni.showToast({ title: res.msg || '提交小结失败', icon: 'none' })
- }
- } catch (err) {
- uni.hideLoading(); console.error('提交宠护小结失败:', err);
- uni.showToast({ title: err.message || err.msg || '提交小结失败', icon: 'none' });
- }
- },
- isVideo(url) {
- if (!url) return false;
- const videoExts = ['.mp4', '.mov', '.m4v', '.3gp', '.avi', '.wmv'];
- return videoExts.some(ext => url.toLowerCase().includes(ext));
- },
- getVideoPoster(url) {
- if (!this.isVideo(url)) return url;
- if (url.includes('?x-oss-process') || url.includes('?ci-process') || url.includes('?vframe')) return url;
- if (url.includes('myqcloud.com')) return url + '?ci-process=snapshot&time=1';
- return url + '?x-oss-process=video/snapshot,t_1,f_jpg,w_300,m_fast';
- },
- previewMedia(medias, currentIdx) {
- const url = medias[currentIdx];
- if (this.isVideo(url)) {
- this.videoPlayerUrl = url; this.videoPlayerShow = true;
- } else {
- const imageUrls = medias.filter(m => !this.isVideo(m));
- const newIdx = imageUrls.indexOf(url);
- uni.previewImage({ current: newIdx >= 0 ? newIdx : 0, urls: imageUrls });
- }
- },
- closeVideoPlayer() { this.videoPlayerShow = false; this.videoPlayerUrl = '' }
- }
- }
- </script>
- <style>
- page {
- background-color: #F8F8F8;
- }
- .detail-container {
- padding-bottom: 200rpx;
- }
- .loading-container {
- padding: 30rpx;
- }
- .skeleton-header {
- background: linear-gradient(135deg, #FF9800 0%, #FF5722 100%);
- border-radius: 20rpx;
- padding: 40rpx;
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 20rpx;
- }
- .skeleton-progress {
- background: linear-gradient(135deg, #FF9800 0%, #FF5722 100%);
- border-radius: 0 0 20rpx 20rpx;
- margin-top: -40rpx;
- padding: 30rpx 40rpx 40rpx;
- display: flex;
- justify-content: space-around;
- margin-bottom: 25rpx;
- }
- .skeleton-circle {
- width: 40rpx;
- height: 40rpx;
- border-radius: 50%;
- background-color: rgba(255, 255, 255, 0.3);
- }
- .skeleton-card {
- background-color: #fff;
- border-radius: 20rpx;
- padding: 30rpx;
- margin-bottom: 25rpx;
- box-shadow: 0 5rpx 20rpx rgba(0, 0, 0, 0.03);
- }
- .skeleton-line {
- border-radius: 8rpx;
- background-color: #f0f0f0;
- }
- .skeleton-ani {
- background: linear-gradient(90deg, #f0f0f0 25%, #e8e8e8 37%, #f0f0f0 63%);
- background-size: 400% 100%;
- animation: skeleton-loading 1.4s ease infinite;
- }
- .skeleton-header .skeleton-ani {
- background: linear-gradient(90deg, rgba(255, 255, 255, 0.2) 25%, rgba(255, 255, 255, 0.35) 37%, rgba(255, 255, 255, 0.2) 63%);
- background-size: 400% 100%;
- animation: skeleton-loading 1.4s ease infinite;
- }
- .skeleton-progress .skeleton-ani {
- background: linear-gradient(90deg, rgba(255, 255, 255, 0.2) 25%, rgba(255, 255, 255, 0.35) 37%, rgba(255, 255, 255, 0.2) 63%);
- background-size: 400% 100%;
- animation: skeleton-loading 1.4s ease infinite;
- }
- @keyframes skeleton-loading {
- 0% {
- background-position: 100% 50%;
- }
- 100% {
- background-position: 0 50%;
- }
- }
- .detail-header {
- background: linear-gradient(135deg, #FF9800 0%, #FF5722 100%);
- padding: 40rpx 40rpx 50rpx 40rpx;
- color: #fff;
- border-radius: 20rpx;
- margin: 30rpx 30rpx 25rpx 30rpx;
- box-shadow: 0 5rpx 15rpx rgba(255, 87, 34, 0.2);
- }
- .status-row {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 40rpx;
- }
- .status-title {
- font-size: 28rpx;
- font-weight: bold;
- }
- .status-fulfillmentCommission {
- font-size: 40rpx;
- font-weight: bold;
- }
- .progress-bar {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- padding: 0 10rpx;
- }
- .step-item {
- display: flex;
- flex-direction: column;
- align-items: center;
- flex: 1;
- position: relative;
- opacity: 0.5;
- }
- .step-item.done {
- opacity: 1;
- }
- .step-item.done .step-circle {
- background-color: #fff;
- color: #FF5722;
- font-weight: bold;
- }
- .step-item.done .step-text {
- font-weight: 500;
- }
- .step-item.active {
- opacity: 1;
- }
- .step-item.active .step-circle {
- background-color: #fff;
- color: #FF5722;
- font-weight: bold;
- width: 48rpx;
- height: 48rpx;
- font-size: 24rpx;
- box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.15);
- }
- .step-item.active .step-text {
- font-weight: bold;
- }
- .step-circle-wrapper {
- position: relative;
- width: 100%;
- display: flex;
- justify-content: center;
- margin-bottom: 10rpx;
- }
- .step-circle {
- width: 40rpx;
- height: 40rpx;
- border-radius: 50%;
- background-color: rgba(255, 255, 255, 0.3);
- color: rgba(255, 255, 255, 0.8);
- font-size: 20rpx;
- display: flex;
- justify-content: center;
- align-items: center;
- position: relative;
- z-index: 2;
- transition: all 0.2s;
- }
- .step-line {
- position: absolute;
- top: 50%;
- right: calc(50% + 20rpx);
- width: calc(100% - 40rpx);
- height: 2rpx;
- background-color: rgba(255, 255, 255, 0.3);
- z-index: 1;
- transform: translateY(-50%);
- }
- .step-line.active-line {
- background-color: #fff;
- height: 3rpx;
- }
- .step-text {
- font-size: 24rpx;
- }
- .detail-content {
- width: 100%;
- box-sizing: border-box;
- padding: 0 30rpx;
- position: relative;
- z-index: 10;
- }
- .white-card {
- background-color: #fff;
- border-radius: 20rpx;
- padding: 30rpx;
- margin-bottom: 25rpx;
- box-shadow: 0 5rpx 20rpx rgba(0, 0, 0, 0.03);
- }
- .pet-bar {
- display: flex;
- align-items: center;
- }
- .pb-avatar {
- width: 100rpx;
- height: 100rpx;
- border-radius: 50%;
- margin-right: 20rpx;
- }
- .pb-info {
- flex: 1;
- display: flex;
- flex-direction: column;
- }
- .pb-name-row {
- margin-bottom: 10rpx;
- }
- .pb-name {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- margin-right: 15rpx;
- }
- .pb-breed {
- font-size: 26rpx;
- color: #999;
- }
- .pb-tags {
- display: flex;
- }
- .pb-tag {
- background-color: #FFF3E0;
- color: #FF9800;
- font-size: 22rpx;
- padding: 4rpx 16rpx;
- border-radius: 8rpx;
- }
- .pb-actions {
- display: flex;
- align-items: center;
- }
- .pb-btn {
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .profile-btn {
- border: 2rpx solid #FF9800;
- color: #FF9800;
- font-size: 24rpx;
- padding: 8rpx 20rpx;
- border-radius: 30rpx;
- margin-right: 20rpx;
- }
- .phone-btn {
- width: 60rpx;
- height: 60rpx;
- border-radius: 50%;
- background-color: #FFF3E0;
- }
- .phone-icon {
- width: 32rpx;
- height: 32rpx;
- }
- .si-row {
- display: flex;
- align-items: flex-start;
- margin-bottom: 30rpx;
- }
- .si-row:last-child {
- margin-bottom: 0;
- }
- .si-icon {
- width: 36rpx;
- height: 36rpx;
- margin-right: 20rpx;
- margin-top: 4rpx;
- }
- .si-icon-uni {
- margin-right: 20rpx;
- margin-top: 4rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .si-content {
- flex: 1;
- display: flex;
- flex-direction: column;
- }
- .si-label {
- font-size: 24rpx;
- color: #999;
- margin-bottom: 6rpx;
- }
- .icon-bg {
- width: 44rpx;
- height: 44rpx;
- border-radius: 8rpx;
- display: flex;
- justify-content: center;
- align-items: center;
- margin-right: 20rpx;
- margin-top: 4rpx;
- flex-shrink: 0;
- }
- .icon-bg.grey-bg {
- background-color: #F8F8F8;
- }
- .custom-icon {
- width: 28rpx;
- height: 28rpx;
- }
- .custom-icon-file {
- width: 36rpx;
- height: 36rpx;
- }
- .si-val {
- font-size: 28rpx;
- color: #333;
- }
- .record-btn {
- font-size: 24rpx;
- color: #FF5722;
- display: flex;
- align-items: center;
- }
- .record-arrow {
- width: 24rpx;
- height: 24rpx;
- margin-left: 6rpx;
- }
- .record-history-row {
- margin-top: 30rpx;
- padding-top: 25rpx;
- border-top: 1px dashed #f0f0f0;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .addr-row {
- position: relative;
- align-items: stretch;
- }
- .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.start {
- background-color: #FFB74D;
- }
- .icon-circle.end {
- background-color: #81C784;
- }
- .icon-circle.service {
- background-color: #81C784;
- }
- .route-line-vertical {
- position: absolute;
- left: 19rpx;
- top: 46rpx;
- bottom: -6rpx;
- border-left: 2rpx dashed #E0E0E0;
- width: 0;
- z-index: 0;
- }
- .si-addr-title {
- font-size: 30rpx;
- font-weight: bold;
- color: #333;
- margin-bottom: 6rpx;
- }
- .si-addr-desc {
- font-size: 24rpx;
- color: #999;
- }
- .nav-btn-circle {
- width: 50rpx;
- height: 50rpx;
- background-color: #FFF3E0;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- margin-top: 6rpx;
- }
- .nav-arrow {
- width: 28rpx;
- height: 28rpx;
- }
- .task-card {
- display: flex;
- flex-direction: column;
- }
- .tc-title {
- font-size: 30rpx;
- font-weight: bold;
- color: #333;
- margin-bottom: 15rpx;
- }
- .tc-desc {
- font-size: 22rpx;
- color: #666;
- margin-bottom: 12rpx;
- }
- .media-grid {
- display: flex;
- flex-wrap: wrap;
- gap: 20rpx;
- margin-bottom: 20rpx;
- }
- .media-item {
- width: 160rpx;
- height: 160rpx;
- position: relative;
- border-radius: 12rpx;
- }
- .media-preview {
- width: 100%;
- height: 100%;
- border-radius: 12rpx;
- }
- .media-del {
- position: absolute;
- top: -10rpx;
- right: -10rpx;
- width: 36rpx;
- height: 36rpx;
- background-color: rgba(0, 0, 0, 0.5);
- color: #fff;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 24rpx;
- z-index: 2;
- }
- .media-add {
- width: 160rpx;
- height: 160rpx;
- border: 2rpx dashed #ccc;
- border-radius: 12rpx;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- background-color: #FAFAFA;
- box-sizing: border-box;
- }
- .upload-icon-small {
- width: 40rpx;
- height: 40rpx;
- margin-bottom: 10rpx;
- }
- .upload-text-small {
- font-size: 22rpx;
- color: #999;
- }
- .full-media-add {
- width: 100%;
- height: 140rpx;
- background-color: #FAFAFA;
- border: 2rpx dashed #E0E0E0;
- border-radius: 12rpx;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- margin-top: 10rpx;
- }
- .upload-icon-large {
- width: 50rpx;
- height: 50rpx;
- margin-bottom: 10rpx;
- opacity: 0.5;
- }
- .upload-text-large {
- font-size: 24rpx;
- color: #999;
- }
- .bi-row {
- display: flex;
- align-items: flex-start;
- margin-bottom: 25rpx;
- }
- .bi-row:last-child {
- margin-bottom: 0;
- }
- .bi-icon {
- width: 32rpx;
- height: 32rpx;
- margin-right: 20rpx;
- margin-top: 4rpx;
- }
- .bi-icon-uni {
- margin-right: 20rpx;
- margin-top: 4rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .bi-content {
- flex: 1;
- display: flex;
- flex-direction: column;
- }
- .bi-label {
- font-size: 24rpx;
- color: #999;
- margin-bottom: 6rpx;
- }
- .bi-val-row {
- display: flex;
- align-items: center;
- }
- .bi-val {
- font-size: 28rpx;
- color: #333;
- }
- .bi-copy {
- background-color: #F0F0F0;
- color: #666;
- font-size: 20rpx;
- padding: 2rpx 10rpx;
- border-radius: 6rpx;
- margin-left: 15rpx;
- }
- .tl-title-row {
- display: flex;
- align-items: center;
- margin-bottom: 30rpx;
- }
- .orange-bar {
- width: 8rpx;
- height: 32rpx;
- background-color: #FF9800;
- margin-right: 16rpx;
- border-radius: 4rpx;
- }
- .tl-title {
- font-size: 30rpx;
- font-weight: bold;
- color: #333;
- }
- .tl-list {
- display: flex;
- flex-direction: column;
- padding-left: 10rpx;
- }
- .tl-item {
- display: flex;
- position: relative;
- padding-bottom: 40rpx;
- }
- .tl-item:last-child {
- padding-bottom: 0;
- }
- .tl-marker {
- width: 16rpx;
- height: 16rpx;
- border-radius: 50%;
- background-color: #E0E0E0;
- position: absolute;
- left: 0;
- top: 6rpx;
- z-index: 2;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .tl-marker.active {
- background-color: #fff;
- border: 3rpx solid #FF9800;
- width: 18rpx;
- height: 18rpx;
- left: -1rpx;
- }
- .tl-dot-inner {
- width: 10rpx;
- height: 10rpx;
- border-radius: 50%;
- background-color: #FF9800;
- }
- .tl-item:not(:last-child)::after {
- content: '';
- position: absolute;
- left: 7rpx;
- top: 24rpx;
- bottom: -6rpx;
- width: 2rpx;
- background-color: #FFE0B2;
- z-index: 1;
- }
- .tl-content-row {
- margin-left: 40rpx;
- display: flex;
- flex-direction: column;
- width: 100%;
- }
- .tl-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- width: 100%;
- margin-bottom: 10rpx;
- }
- .tl-status {
- font-size: 28rpx;
- color: #333;
- font-weight: 500;
- }
- .tl-time {
- font-size: 24rpx;
- color: #999;
- }
- .tl-medias {
- display: flex;
- flex-wrap: wrap;
- gap: 15rpx;
- margin-bottom: 15rpx;
- }
- .tl-img {
- width: 140rpx;
- height: 140rpx;
- border-radius: 8rpx;
- }
- .tl-remark {
- font-size: 24rpx;
- color: #666;
- background-color: #F9F9F9;
- padding: 15rpx;
- border-radius: 8rpx;
- line-height: 1.5;
- }
- .bottom-action-bar {
- position: fixed;
- bottom: 0;
- left: 0;
- width: 100%;
- height: 120rpx;
- background-color: #fff;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 30rpx;
- box-shadow: 0 -5rpx 20rpx rgba(0, 0, 0, 0.05);
- box-sizing: border-box;
- padding-bottom: constant(safe-area-inset-bottom);
- padding-bottom: env(safe-area-inset-bottom);
- z-index: 100;
- }
- .action-left,
- .action-right {
- display: flex;
- align-items: center;
- }
- .action-btn {
- height: 64rpx;
- line-height: 64rpx;
- border-radius: 32rpx;
- font-size: 26rpx;
- padding: 0 35rpx;
- margin: 0;
- }
- .action-left .action-btn:first-child {
- margin-right: 20rpx;
- }
- .action-btn.grey-outline {
- background-color: #fff;
- color: #666;
- border: 1px solid #E0E0E0;
- }
- .action-btn.orange-outline {
- background-color: #FFF8F0;
- color: #FF9800;
- border: 1px solid #FF9800;
- }
- .action-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;
- }
- .action-btn.grey-bg {
- background: #E0E0E0;
- color: #999;
- box-shadow: none;
- border: none;
- }
- .action-btn::after {
- border: none;
- }
- .upload-modal-mask {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.4);
- z-index: 999;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .upload-modal-content {
- width: 600rpx;
- background-color: #ffffff;
- border-radius: 20rpx;
- padding: 40rpx;
- box-sizing: border-box;
- display: flex;
- flex-direction: column;
- }
- .um-header {
- text-align: center;
- margin-bottom: 40rpx;
- }
- .um-title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- }
- .um-remark-hint {
- display: block;
- font-size: 22rpx;
- color: #999;
- margin-top: 16rpx;
- line-height: 1.4;
- }
- .um-grid {
- display: flex;
- flex-wrap: wrap;
- margin-bottom: 30rpx;
- }
- .um-item {
- width: 130rpx;
- height: 130rpx;
- border-radius: 8rpx;
- margin-right: 20rpx;
- margin-bottom: 20rpx;
- position: relative;
- background-color: #f5f5f5;
- overflow: hidden;
- }
- .um-item:nth-child(4n) {
- margin-right: 0;
- }
- .um-preview {
- width: 100%;
- height: 100%;
- }
- .um-del {
- position: absolute;
- top: 4rpx;
- right: 4rpx;
- width: 36rpx;
- height: 36rpx;
- line-height: 32rpx;
- text-align: center;
- background-color: rgba(0, 0, 0, 0.5);
- color: #fff;
- border-radius: 50%;
- font-size: 28rpx;
- z-index: 10;
- }
- .um-video-badge {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- background-color: rgba(0, 0, 0, 0.2);
- z-index: 5;
- }
- .play-icon-small {
- width: 48rpx;
- height: 48rpx;
- opacity: 0.9;
- }
- .um-add {
- width: 130rpx;
- height: 130rpx;
- border-radius: 8rpx;
- border: 1px dashed #e5e5e5;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- box-sizing: border-box;
- margin-bottom: 20rpx;
- }
- .um-add-icon {
- width: 44rpx;
- height: 44rpx;
- margin-bottom: 10rpx;
- opacity: 0.4;
- }
- .um-add-text {
- font-size: 24rpx;
- color: #ccc;
- }
- .um-textarea {
- width: 100%;
- height: 160rpx;
- background-color: #ffffff;
- border-radius: 12rpx;
- padding: 24rpx;
- font-size: 28rpx;
- color: #333;
- box-sizing: border-box;
- border: 1px solid #f0f0f0;
- }
- .um-footer {
- margin-top: 40rpx;
- display: flex;
- justify-content: center;
- }
- .um-submit-btn {
- width: 100%;
- height: 88rpx;
- line-height: 88rpx;
- border-radius: 44rpx;
- font-size: 32rpx;
- background-color: #E0E0E0;
- color: #fff;
- border: none;
- text-align: center;
- }
- .um-submit-btn.active {
- background: linear-gradient(90deg, #FF9800 0%, #FF5722 100%);
- color: #fff;
- box-shadow: 0 4rpx 10rpx rgba(255, 87, 34, 0.3);
- }
- .um-submit-btn::after {
- border: none;
- }
- .pet-modal-mask {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.5);
- z-index: 999;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .pet-modal-content {
- width: 680rpx;
- max-height: 85vh;
- background-color: #fff;
- border-radius: 20rpx;
- display: flex;
- flex-direction: column;
- overflow: hidden;
- box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.15);
- }
- .pet-modal-header {
- display: flex;
- align-items: center;
- padding: 30rpx 30rpx 20rpx;
- border-bottom: 1px solid #f5f5f5;
- flex-shrink: 0;
- }
- .pet-modal-title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- }
- .close-icon-btn {
- width: 52rpx;
- height: 52rpx;
- line-height: 52rpx;
- text-align: center;
- font-size: 36rpx;
- color: #999;
- border-radius: 50%;
- background-color: #f5f5f5;
- flex-shrink: 0;
- }
- .pm-remark-btn {
- height: 52rpx;
- line-height: 52rpx;
- padding: 0 24rpx;
- background: linear-gradient(90deg, #FF9800 0%, #FF5722 100%);
- color: #fff;
- font-size: 26rpx;
- border-radius: 26rpx;
- margin-right: 16rpx;
- font-weight: bold;
- flex-shrink: 0;
- }
- .pet-modal-scroll {
- flex: 1;
- height: 65vh;
- overflow: auto;
- }
- .pet-base-info {
- display: flex;
- align-items: center;
- padding: 24rpx 30rpx;
- border-bottom: 1px solid #f9f9f9;
- }
- .pm-avatar {
- width: 100rpx;
- height: 100rpx;
- border-radius: 50%;
- margin-right: 20rpx;
- flex-shrink: 0;
- }
- .pm-info-text {
- flex: 1;
- display: flex;
- flex-direction: column;
- }
- .pm-name-row {
- display: flex;
- align-items: center;
- margin-bottom: 8rpx;
- }
- .pm-name {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- margin-right: 12rpx;
- }
- .pm-gender {
- display: flex;
- align-items: center;
- background-color: #E3F2FD;
- color: #1976D2;
- font-size: 22rpx;
- padding: 2rpx 10rpx;
- border-radius: 10rpx;
- }
- .pm-gender.female {
- background-color: #FCE4EC;
- color: #C2185B;
- }
- .gender-icon {
- font-size: 22rpx;
- margin-right: 4rpx;
- }
- .pm-breed {
- font-size: 26rpx;
- color: #999;
- }
- .pm-detail-grid {
- padding: 20rpx 30rpx;
- display: flex;
- flex-wrap: wrap;
- gap: 16rpx;
- border-bottom: 1px solid #f9f9f9;
- }
- .pm-grid-item {
- background-color: #FAFAFA;
- border-radius: 12rpx;
- padding: 16rpx 20rpx;
- display: flex;
- flex-direction: column;
- }
- .pm-grid-item.half {
- width: calc(50% - 8rpx);
- }
- .pm-grid-item.full {
- width: 100%;
- }
- .pm-label {
- font-size: 24rpx;
- color: #999;
- margin-bottom: 8rpx;
- }
- .pm-val {
- font-size: 28rpx;
- color: #333;
- line-height: 1.5;
- }
- .pm-tags-row {
- display: flex;
- flex-wrap: wrap;
- padding: 0 24rpx 20rpx;
- gap: 16rpx;
- }
- .pm-tag-chip {
- background-color: #FFF3E0;
- border: 1px solid #FFB74D;
- border-radius: 20rpx;
- padding: 6rpx 20rpx;
- }
- .pm-tag-chip-text {
- font-size: 24rpx;
- color: #FF9800;
- }
- .pm-log-section {
- padding: 20rpx 24rpx;
- border-top: 1px solid #f5f5f5;
- margin-top: 10rpx;
- }
- .pm-log-header {
- display: flex;
- align-items: center;
- margin-bottom: 20rpx;
- }
- .pm-log-section-title {
- font-size: 28rpx;
- font-weight: bold;
- color: #333;
- }
- .pm-log-item {
- padding: 16rpx 0;
- border-bottom: 1px solid #f9f9f9;
- display: flex;
- flex-direction: column;
- }
- .pm-log-date {
- font-size: 24rpx;
- color: #999;
- margin-bottom: 8rpx;
- }
- .pm-log-text {
- font-size: 28rpx;
- color: #333;
- line-height: 1.6;
- margin-bottom: 6rpx;
- }
- .pm-log-recorder {
- font-size: 22rpx;
- color: #FF9800;
- text-align: right;
- }
- .pm-log-recorder.system {
- color: #999;
- }
- .pm-bottom-close {
- margin: 16rpx 30rpx;
- height: 72rpx;
- line-height: 72rpx;
- border-radius: 36rpx;
- font-size: 28rpx;
- background-color: #f5f5f5;
- color: #666;
- border: none;
- }
- .pm-bottom-close::after {
- border: none;
- }
- .sum-modal-mask {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.5);
- z-index: 999;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .sum-modal-card {
- width: 660rpx;
- max-height: 80vh;
- background-color: #fff;
- border-radius: 20rpx;
- display: flex;
- flex-direction: column;
- overflow: hidden;
- box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.15);
- }
- .sum-modal-scroll {
- flex: 1;
- overflow: hidden;
- }
- .sum-modal-inner {
- padding: 32rpx 36rpx 0;
- }
- .sum-modal-title {
- display: block;
- font-size: 34rpx;
- font-weight: bold;
- color: #333;
- text-align: center;
- margin-bottom: 30rpx;
- }
- .sum-meta-row {
- display: flex;
- margin-bottom: 16rpx;
- align-items: flex-start;
- }
- .sum-meta-label {
- font-size: 26rpx;
- color: #999;
- flex-shrink: 0;
- width: 140rpx;
- }
- .sum-meta-val {
- font-size: 24rpx;
- color: #333;
- flex: 1;
- }
- .sum-section-title {
- font-size: 26rpx;
- font-weight: bold;
- color: #333;
- padding-left: 12rpx;
- border-left: 6rpx solid #FF9800;
- margin-top: 24rpx;
- margin-bottom: 16rpx;
- }
- .sum-pet-card {
- background-color: #FAFAFA;
- border-radius: 12rpx;
- padding: 20rpx;
- display: flex;
- align-items: center;
- }
- .sum-pet-avatar {
- width: 80rpx;
- height: 80rpx;
- border-radius: 50%;
- margin-right: 20rpx;
- flex-shrink: 0;
- }
- .sum-pet-info {
- flex: 1;
- display: flex;
- flex-direction: column;
- }
- .sum-pet-name-row {
- display: flex;
- align-items: center;
- margin-bottom: 8rpx;
- }
- .sum-pet-name {
- font-size: 26rpx;
- font-weight: bold;
- color: #333;
- margin-right: 12rpx;
- }
- .sum-pet-breed {
- font-size: 24rpx;
- color: #999;
- }
- .sum-pet-remark {
- font-size: 24rpx;
- color: #666;
- line-height: 1.5;
- }
- .sum-textarea {
- width: 100%;
- min-height: 220rpx;
- background-color: #fff;
- border: 1px solid #eeeeee;
- border-radius: 12rpx;
- padding: 18rpx;
- font-size: 26rpx;
- color: #333;
- box-sizing: border-box;
- line-height: 1.8;
- }
- .sum-sign-row {
- display: flex;
- align-items: center;
- margin-top: 30rpx;
- padding: 16rpx 0;
- border-top: 1px solid #f5f5f5;
- }
- .sum-sign-label {
- font-size: 26rpx;
- color: #999;
- margin-right: 10rpx;
- }
- .sum-sign-val {
- font-size: 26rpx;
- color: #333;
- }
- .sum-footer {
- padding: 20rpx 36rpx 36rpx;
- padding-bottom: max(36rpx, constant(safe-area-inset-bottom));
- padding-bottom: max(36rpx, env(safe-area-inset-bottom));
- background-color: #fff;
- }
- .sum-submit-btn {
- width: 100%;
- height: 84rpx;
- line-height: 84rpx;
- border-radius: 42rpx;
- font-size: 30rpx;
- background: linear-gradient(90deg, #FF9800 0%, #FF5722 100%);
- color: #fff;
- border: none;
- box-shadow: 0 4rpx 16rpx rgba(255, 87, 34, 0.25);
- }
- .sum-submit-btn::after {
- border: none;
- }
- .modal-mask {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.5);
- z-index: 999;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .anomaly-modal-content {
- width: 650rpx;
- background-color: #fff;
- border-radius: 20rpx;
- padding: 30rpx;
- position: relative;
- max-height: 80vh;
- display: flex;
- flex-direction: column;
- }
- .am-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 30rpx;
- padding-bottom: 20rpx;
- border-bottom: 1px solid #f5f5f5;
- }
- .am-title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- }
- .am-scroll-list {
- flex: 1;
- }
- .am-item {
- padding: 24rpx;
- background-color: #F9FAFB;
- border-radius: 12rpx;
- margin-bottom: 24rpx;
- }
- .am-item-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 16rpx;
- }
- .am-item-type {
- font-size: 28rpx;
- font-weight: bold;
- color: #333;
- }
- .am-item-status {
- font-size: 22rpx;
- padding: 4rpx 16rpx;
- border-radius: 20rpx;
- }
- .am-item-status.status-0 {
- background-color: #FFF3E0;
- color: #FF9800;
- }
- .am-item-status.status-1 {
- background-color: #E8F5E9;
- color: #4CAF50;
- }
- .am-item-status.status-2 {
- background-color: #FFEBEE;
- color: #F44336;
- }
- .am-item-content {
- font-size: 26rpx;
- color: #666;
- line-height: 1.6;
- display: block;
- margin-bottom: 16rpx;
- }
- .am-item-photos {
- display: flex;
- flex-wrap: wrap;
- gap: 12rpx;
- margin-bottom: 20rpx;
- }
- .am-photo {
- width: 130rpx;
- height: 130rpx;
- border-radius: 8rpx;
- }
- .am-audit-box {
- margin-top: 20rpx;
- padding-top: 20rpx;
- border-top: 1px dashed #E0E0E0;
- }
- .am-audit-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 8rpx;
- }
- .am-audit-label {
- font-size: 24rpx;
- font-weight: bold;
- color: #333;
- }
- .am-audit-time {
- font-size: 22rpx;
- color: #999;
- }
- .am-audit-remark {
- font-size: 24rpx;
- color: #666;
- line-height: 1.5;
- }
- .empty-list {
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 100rpx 0;
- }
- .empty-icon {
- width: 200rpx;
- height: 200rpx;
- margin-bottom: 20rpx;
- opacity: 0.5;
- }
- .empty-text {
- font-size: 26rpx;
- color: #999;
- }
- .tl-media-item {
- position: relative;
- width: 140rpx;
- height: 140rpx;
- }
- .tl-video-placeholder {
- width: 100%;
- height: 100%;
- background: linear-gradient(135deg, #444 0%, #222 100%);
- border-radius: 8rpx;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- }
- .tl-video-placeholder.miniaturized {
- border-radius: 8rpx;
- overflow: hidden;
- }
- .tl-video-label {
- color: #fff;
- font-size: 20rpx;
- margin-top: 50rpx;
- opacity: 0.8;
- }
- .tl-video-label.small {
- margin-top: 35rpx;
- font-size: 18rpx;
- }
- .tl-play-icon {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- width: 60rpx;
- height: 60rpx;
- display: flex;
- justify-content: center;
- align-items: center;
- background-color: rgba(255, 255, 255, 0.2);
- border: 2rpx solid #fff;
- border-radius: 50%;
- }
- .tl-play-icon::after {
- content: '';
- display: block;
- width: 0;
- height: 0;
- border-top: 15rpx solid transparent;
- border-bottom: 15rpx solid transparent;
- border-left: 20rpx solid #fff;
- margin-left: 6rpx;
- }
- .tl-play-icon.small {
- width: 40rpx;
- height: 40rpx;
- }
- .tl-play-icon.small::after {
- border-top: 10rpx solid transparent;
- border-bottom: 10rpx solid transparent;
- border-left: 14rpx solid #fff;
- margin-left: 4rpx;
- }
- .video-player-mask {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.9);
- z-index: 999;
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .video-player-content {
- position: relative;
- width: 100%;
- height: 600rpx;
- }
- .v-player {
- width: 100%;
- height: 100%;
- }
- .v-close {
- position: absolute;
- top: -80rpx;
- right: 40rpx;
- width: 60rpx;
- height: 60rpx;
- background-color: rgba(255, 255, 255, 0.2);
- color: #fff;
- border-radius: 50%;
- display: flex;
- justify-content: center;
- align-items: center;
- font-size: 40rpx;
- }
- .am-photo-item {
- position: relative;
- width: 150rpx;
- height: 150rpx;
- border-radius: 8rpx;
- overflow: hidden;
- }
- .am-photo {
- width: 150rpx;
- height: 150rpx;
- border-radius: 8rpx;
- }
- .nav-modal-mask {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.6);
- z-index: 1000;
- display: flex;
- align-items: flex-end;
- }
- .nav-action-sheet {
- width: 100%;
- background-color: #fff;
- border-radius: 30rpx 30rpx 0 0;
- padding-bottom: constant(safe-area-inset-bottom);
- padding-bottom: env(safe-area-inset-bottom);
- overflow: hidden;
- }
- .nav-sheet-title {
- display: block;
- text-align: center;
- font-size: 26rpx;
- color: #999;
- padding: 30rpx 0;
- border-bottom: 1px solid #f5f5f5;
- }
- .nav-sheet-item {
- display: block;
- text-align: center;
- font-size: 32rpx;
- color: #333;
- padding: 35rpx 0;
- border-bottom: 1px solid #f5f5f5;
- background-color: #fff;
- }
- .nav-sheet-item:active {
- background-color: #f9f9f9;
- }
- .nav-sheet-item.cancel {
- color: #999;
- }
- .nav-sheet-gap {
- height: 12rpx;
- background-color: #f5f5f5;
- }
- </style>
|