| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637 |
- <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.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>
|