微信开发者工具
{"title":"接口异常 DescribeAppPubUrl","description":"[ResourceNotFound]应用不存在或者无访问权限[RequestId:d9ed30f1-3c88-4e84-a9d2-f9c64dd6e63a]","envId":"cloudbase-7g86dx1w97ec6954","wxAppId":"wx81847f495d62d96e","uin":"100046549614","v":"2.1.6","Code":"ResourceNotFound","Message":"应用不存在或者无访问权限","BFFRequestId":"652c2eb5-a6c2-4174-a3aa-01ea03461e41","RequestId":"d9ed30f1-3c88-4e84-a9d2-f9c64dd6e63a"}
chooseMessageFile选择文件拿到路径后由readFileSync读取不到。返回路径不存在。将路径交给accessSync去判断,也返回路径不存在 此问题在4月8日,有许多安卓用户反馈,但无线上日志。在开发者工具中复现,在基础版本3.15.1和3.15.2均出现。 wx.chooseMessageFile({ count: 1, type: "file", success: (data) => { console.log(data) let {tempFiles} = data wx.getFileSystemManager().access({ path: tempFiles[0].path, success(res) { // 文件存在 console.log(res, "存在") }, fail(res) { // 文件不存在或其他错误 console.error(res, "不存在") } }) }, fail: (err) => { console.error(err) } }) [图片]
[图片][图片]
<!-- index.wxml --> <view class="container"> <view class="map-container"> <map id="myMap" longitude="{{center.longitude}}" latitude="{{center.latitude}}" scale="{{scale}}" show-location="true" ground-overlays="{{groundOverlays}}" bindregionchange="onRegionChange" style="width: 100%; height: 100%;"></map> </view> <!-- 调试信息 --> <view class="debug-info"> <text>地图中心: {{center.longitude}}, {{center.latitude}}</text> <text>缩放级别: {{scale}}</text> <text>覆盖物数量: {{groundOverlays.length}}</text> <image src="/image/hangzhou-hangzhou_walnut.png" style="width: 100px; height: 100px; margin-top: 10px;" /> </view> </view> // index.js Page({ data: { groundOverlays: [], center: { longitude: 119.2699, latitude: 29.8241 }, scale: 10 }, onLoad() { console.log('页面加载,开始添加WMS图片覆盖物'); // 本地图片路径 const imageUrl = '/image/hangzhou-hangzhou_walnut.png'; console.log('图片路径:', imageUrl); // 定义覆盖物的边界 const bounds = { southwest: { latitude: 29.20549983500007, longitude: 118.42544671700011 }, northeast: { latitude: 30.442736612000058, longitude: 120.11447879 } }; console.log('覆盖物边界:', bounds); const groundOverlays = [{ id: 'wms-overlay', src: imageUrl, bounds: bounds, opacity: 0.7 // 添加透明度,确保能看到 }]; console.log('groundOverlays:', groundOverlays); this.setData({ groundOverlays }, function() { console.log('WMS图片覆盖物添加成功'); }); }, onReady() { // 监听地图加载完成 this.mapCtx = wx.createMapContext('myMap', this); // 延迟设置,确保地图完全加载 setTimeout(() => { console.log('地图加载完成,检查覆盖物'); // 获取地图信息 this.mapCtx.getCenterLocation({ success: (res) => { console.log('地图中心点:', res); } }); }, 1000); }, // 添加地图事件监听 onRegionChange(e) { console.log('地图区域变化:', e); } })
version: stable 2.01.2510290 复现流程: 如下图,我的一个index.wxml页面,我之前已经在git提交过了,没有任何问题,但是当我在页面上点击ctrl + s 就会出现一个待提交; 然后页面样式也稍微有一些问题,会有空白格。 这是什么问题? 怎么解决 [图片] 然后我自己排查了一下,发现当我通过git回滚后,查看文件编码,开头是正确的 3C 76 69; 当我按下ctrl + s 文件变成 EF BB BF 如图 [图片] 最后我又在vscode上,进行修改代码,然后保存确实没有出现问题。 后面我又在开发者工具 就会出现; (vs) [图片] (wx) [图片]
uniapp小程序中有引入插件时,无法运行(旧版本的微信开发者工具可以)。 [图片][图片][图片]
公司网络使用深信服后,微信开发者工具经常报网络错误,导致无法编译与调试:Error: SystemError (appServiceSDKScriptError) {"errMsg":"webapi_getwxaasyncsecinfo:fail Failed to fetch"} 微信开发者工具调试日志:xxx\微信web开发者工具\code\package.nw\core.wxvpkg\0b6e4b3dce6396a86cf6febb45c187c3.js:9 [2026-04-09 15:59:42.921][ERROR][unknow][\core.wxvpkg\3f831e7255c55b0464f2f1c29d9d043e.js] https://servicewechat.com/wxa-dev-logic/ideoptconf?appid=wxxxxxxx TypeError: Failed to fetch
[图片][图片] 试过卸载重装,调整网络代理,重连网络,切换别人网络、校园网都没用,学校布置作业也没法交!!!!
https://developers.weixin.qq.com/miniprogram/dev/devtools/log.html
[图片][图片][图片]
我们是自研的WMS,然后客户用的ERP是额外采购的,也就是客户采购了A公司的ERP和我司的WMS 调取微信视频号,获取快递单号时,需要购买我司WMS的服务,但是买服务限定死了只能有一个ERP类型的,买了我们的就必须解绑ERP,不买我们的,又没办法跨店铺代发了(官方公告20号后不允许),我们现在需要怎么做
相同的代码使用 miniprogram-ci 2.1.26 版本进行代码的上传 主包2012kb, 在开发者工具看主包大小也是2012kb。 但是使用版本miniprogram-ci 2.1.32 进行代码上传 主包大小就直接到了2674kb。[图片] 不知道新版本的cli里面做了什么,导致主包大了这么多。 这是使用老版本的cli正常上传代码的截图主包大小并没有提示超限制。 [图片]
没升级前点击“云开发”没有反应,马上更新。更新后,版面变了。云开发只有一个小图标在右上角偏中间的位置。但点击没有反应。之前应该是打开的一个云开发的一个网站页面的,能看到文档、数据库等页面
请问有人知道怎么解决吗?[图片]之前觉得名字太长了,就换了一个名字短的,[图片]但还是失败。
版本 2.01.2510290mac系统 今天更新微信开发者工具后,模拟器在分离窗口模式代码热更新失效了,模拟器在IDE里代码热更新是有效的。
[图片]
域名没变后端切换了ip之后,在微信开发者工具中,域名请求访问不到了,但是ip直接访问可以。对应的域名请求完整路径放在浏览器中可以正常获取数据。发布在线上的小程序也访问不了了。域名白名单之前都有配置的。appid:wx876a07306622b963 。 基础库版本:3.15.1 [图片][图片][图片][图片][图片]
POST https://api.weixin.qq.com/wxa/sec/order/set_msg_jump_path?access_token=ACCESS_TOKEN 现在每分钟才几十就一直报错 :44990,"errmsg":"reach max api second frequence limit
报错提示 message:Error: 非法的文件,错误信息:invalid file: pages/index/Order-Processing.js, 1:3179, SyntaxError: Unexpected token ?"use strict";const e=require("../../common/vendor.js"),t=require("../../utils/config.js"),s={data:()=>({keyword:"",searchType:"order_no",showTypePicker:!1,searchTypes:[{label:"订单号",key:"order_no"},{label:"客户姓名",key:"nickname"},{label:"手机号",key:"mobile"},{label:"商品名称",key:"goods_name"}],orderList:[],page:1,total:0,loading:!1,refreshing:!1,noMore:!1,currentStatus:-1,shipPopup:null,shipOrder:null,shipMode:1,shipGoodsList:[],shipping:!1,shipForm:{express_id:null,express_name:"",express_no:"",remark:""},expressList:[],expressLoading:!1,showExpressPicker:!1,logisticsPopup:null,logisticsPackages:[],logisticsPkgIndex:0,currentTrack:null,logisticsLoading:!1,showAfterSaleSheet:!1,afterSaleOrder:null,cancelPopup:null,cancelOrder:null,cancelGoodsList:[],cancelSelectedIds:[],tabList:[{name:"全部",status:-1,countKey:"total",count:0},{name:"待到货",status:1,countKey:"pending",count:0},{name:"待补款",status:2,countKey:"unpai... [20260408 17:27:55][wx3ea54ec4fa7cf43a] appid: wx3ea54ec4fa7cf43a openid: o6zAJs9Kr1RwvyYPUf4FQkAJn-pY ideVersion: 2.01.2510260 osType: win32-x64 time: 2026-04-08 17:29:19 <template> <view class="content"> <!-- 搜索栏 --> <view class="search-box"> <view class="search-row"> <view class="search-select" @click="showTypePicker = true"> <text>{{currentTypeLabel}}</text> <uv-icon name="arrow-down" size="22rpx" color="#666"></uv-icon> </view> <input class="search-input" v-model="keyword" :placeholder="currentPlaceholder" confirm-type="search" @confirm="onSearch" /> <view class="search-btn" @click="onSearch">搜索</view> </view> </view> <!-- 搜索类型选择器 --> <view class="type-mask" v-if="showTypePicker" @click="showTypePicker=false"></view> <view class="type-sheet" :class="{show: showTypePicker}"> <view class="type-sheet-title">选择搜索类型</view> <view class="type-sheet-item" v-for="t in searchTypes" :key="t.key" :class="{active: searchType === t.key}" @click="onSelectType(t)"> {{t.label}} <uv-icon v-if="searchType === t.key" name="checkmark" color="#0D69EF" size="32rpx"></uv-icon> </view> <view class="type-sheet-cancel" @click="showTypePicker=false">取消</view> </view> <!-- 状态 Tab --> <uv-sticky offset-top="0" bgColor="#fff"> <uv-tabs :list="tabListDisplay" lineWidth="70rpx" lineColor="#0D69EF" @click="changeTab"></uv-tabs> </uv-sticky> <!-- 订单列表 --> <scroll-view scroll-y class="order-scroll" @scrolltolower="loadMore" refresher-enabled @refresherrefresh="onRefresh" :refresher-triggered="refreshing"> <view class="order-list"> <view class="order-card" v-for="order in orderList" :key="order.id" @click="goDetail(order)"> <!-- 头部 --> <view class="order-head"> <view class="order-head-left"> <text class="order-member">{{order.member_info && order.member_info.nickname || '-'}}</text> <text class="order-store" v-if="order.store_info">{{order.store_info.name}}</text> </view> <text class="order-status-tag" :class="'s'+order.order_status"> {{statusMap[order.order_status] || '-'}} </text> </view> <!-- 订单号 --> <view class="order-no-row"> <text class="order-no">{{order.order_id}}</text> <text class="order-type-tag">{{orderTypeMap[order.order_type] || '普通订单'}}</text> <text v-if="hasPartialCancelled(order.goods_list)" class="partial-cancel-tag">部分取消</text> <text v-if="order.shipping_info && order.shipping_info.length > 0 && order.order_status === 3" class="partial-ship-tag">部分发货</text> </view> <!-- 商品列表(最多展示2个) --> <view class="goods-row" v-for="(g, gi) in (order.goods_list || []).slice(0, 2)" :key="gi"> <uv-image :src="g.goods_image" radius="8rpx" width="100rpx" height="100rpx" mode="aspectFill"></uv-image> <view class="goods-info"> <text class="goods-name ellipsis1">{{g.goods_name}}</text> <text class="goods-spec" v-if="g.spec_data && typeof g.spec_data === 'object' && Object.keys(g.spec_data).length"> {{formatSpec(g.spec_data)}} </text> <view class="goods-price-row"> <text class="goods-price">¥{{g.goods_price}}</text> <text class="goods-num">×{{g.goods_num}}</text> </view> </view> </view> <view class="more-goods" v-if="(order.goods_list || []).length > 2"> <text>共{{order.goods_list.length}}件商品</text> </view> <!-- 底部 --> <view class="order-foot"> <text class="order-time">{{order.order_time}}</text> <view class="order-amount"> <text class="amount-label">实付</text> <text class="amount-val">¥{{order.actual_payment}}</text> </view> </view> <!-- 操作按钮 --> <view class="order-actions" v-if="getActions(order).length" @click.stop> <template v-for="(act, ai) in getActions(order)" :key="ai"> <view v-if="act.action === 'afterSale'" class="action-btn outline after-sale-btn" @click="openAfterSaleSheet(order)"> 售后操作 <uv-icon name="arrow-down" size="20rpx" color="#666" style="margin-left:4rpx"></uv-icon> </view> <view v-else class="action-btn" :class="act.type" @click="handleAction(act, order)"> {{act.label}} </view> </template> </view> </view> </view> <view class="load-tip" v-if="orderList.length > 0"> <text v-if="loading">加载中...</text> <text v-else-if="noMore">没有更多了</text> </view> <view class="empty-box" v-if="!loading && orderList.length === 0"> <uv-empty mode="order" text="暂无订单"></uv-empty> </view> </scroll-view> <!-- 发货弹窗 --> <uv-popup ref="shipPopup" mode="bottom" round="20rpx" :safeAreaInsetBottom="true"> <view class="ship-popup"> <view class="ship-popup-header"> <view> <text class="ship-popup-title">订单发货</text> <text class="ship-popup-no">{{shipOrder && shipOrder.order_id}}</text> </view> <uv-icon name="close" size="36rpx" color="#999" @click="shipPopup.close()"></uv-icon> </view> <!-- 发货模式 --> <view class="ship-mode-row"> <view class="ship-mode-item" :class="{ active: shipMode === 1 }" @click="setShipMode(1)"> <view class="ship-mode-dot" :class="{ active: shipMode === 1 }"></view> <text>整单发货</text> </view> <view class="ship-mode-item" :class="{ active: shipMode === 2, disabled: !canSplitShip }" @click="canSplitShip && setShipMode(2)"> <view class="ship-mode-dot" :class="{ active: shipMode === 2 }"></view> <text>多包裹发货</text> </view> </view> <scroll-view scroll-y style="max-height: 60vh;"> <!-- 分单模式:商品选择 --> <view v-if="shipMode === 2" class="split-goods-section"> <view class="split-tip">选择本次要发货的商品</view> <view v-for="g in shipGoodsList" :key="g.id" class="split-goods-item" :class="{ selected: g._selected, disabled: g.status === 2 || g._availableQty <= 0 }" @click="g.status !== 2 && g._availableQty > 0 && (g._selected = !g._selected)"> <view class="check-box" :class="{ checked: g._selected }"> <uv-icon v-if="g._selected" name="checkmark" size="22rpx" color="#fff"></uv-icon> </view> <uv-image :src="g.goods_image" width="88rpx" height="88rpx" radius="8rpx" mode="aspectFill" style="flex-shrink:0"></uv-image> <view class="split-goods-info"> <view class="split-goods-name-row"> <text class="split-goods-name">{{g.goods_name}}</text> <text v-if="g.status === 2" class="tag-cancelled">已取消</text> <text v-else-if="g._shippedQty >= g.goods_num" class="tag-shipped">已发完</text> <text v-else-if="g._shippedQty > 0" class="tag-partial">部分发货</text> </view> <text class="split-goods-spec" v-if="g.spec_data && Object.keys(g.spec_data).length"> {{Object.entries(g.spec_data).map(([k,v])=>k+':'+v).join(' ')}} </text> <view class="split-goods-qty-row" v-if="g._selected"> <text class="split-qty-label">发货数量</text> <view class="qty-ctrl"> <view class="qty-btn" @click.stop="g.ship_qty > 1 && g.ship_qty--">-</view> <text class="qty-num">{{g.ship_qty}}</text> <view class="qty-btn" @click.stop="g.ship_qty < g._availableQty && g.ship_qty++">+</view> </view> <text class="qty-hint">可发 {{g._availableQty}}</text> </view> <view class="split-goods-qty-row" v-else> <text class="qty-hint">总数 {{g.goods_num}},已发 {{g._shippedQty}},可发 {{g._availableQty}}</text> </view> </view> </view> </view> <!-- 整单模式:商品预览 --> <view v-else class="whole-goods-section"> <view v-for="g in shipGoodsList" :key="g.id" class="whole-goods-item" :class="{ cancelled: g.status === 2, shipped: g._availableQty <= 0 && g.status !== 2 }"> <uv-image :src="g.goods_image" width="80rpx" height="80rpx" radius="8rpx" mode="aspectFill" style="flex-shrink:0"></uv-image> <view class="whole-goods-info"> <view class="whole-goods-name-row"> <text class="whole-goods-name">{{g.goods_name}}</text> <text v-if="g.status === 2" class="tag-cancelled">已取消</text> <text v-else-if="g._availableQty <= 0" class="tag-shipped">已发完</text> <text v-else-if="g._shippedQty > 0" class="tag-partial">部分发货</text> </view> <text class="whole-goods-spec" v-if="g.spec_data && Object.keys(g.spec_data).length"> {{Object.entries(g.spec_data).map(([k,v])=>k+':'+v).join(' ')}} </text> <view class="whole-goods-price-row"> <text class="whole-goods-price">¥{{g.goods_price}}</text> <text class="whole-goods-qty">x{{g.goods_num}}</text> <text class="whole-goods-shipped" v-if="g._shippedQty > 0">已发 {{g._shippedQty}}</text> </view> </view> </view> </view> <!-- 快递信息 --> <view class="ship-form-section"> <view class="ship-form-item" @click="showExpressPicker = true"> <text class="ship-form-label">快递公司 <text class="req">*</text></text> <view class="ship-form-input-row"> <text :class="shipForm.express_name ? 'ship-form-val' : 'ship-form-placeholder'"> {{shipForm.express_name || '请选择快递公司'}} </text> <uv-icon name="arrow-down" size="24rpx" color="#ccc"></uv-icon> </view> </view> <view class="ship-form-item"> <text class="ship-form-label">快递单号 <text class="req">*</text></text> <input class="ship-form-input" v-model="shipForm.express_no" placeholder="请输入快递单号" /> </view> <view class="ship-form-item"> <text class="ship-form-label">发货备注</text> <input class="ship-form-input" v-model="shipForm.remark" placeholder="选填" /> </view> </view> </scroll-view> <view class="ship-popup-footer"> <view class="ship-cancel-btn" @click="shipPopup.close()">取消</view> <view class="ship-confirm-btn" :class="{ loading: shipping }" @click="confirmShip"> {{shipping ? '发货中...' : '确认发货'}} </view> </view> </view> </uv-popup> <!-- 快递公司选择 --> <view class="type-mask" v-if="showExpressPicker" @click="showExpressPicker = false"></view> <view class="type-sheet" :class="{ show: showExpressPicker }"> <view class="type-sheet-title">选择快递公司</view> <view v-if="expressLoading" class="type-sheet-loading"> <uv-loading-icon mode="circle" size="40rpx"></uv-loading-icon> </view> <view v-else class="type-sheet-item" v-for="e in expressList" :key="e.id" :class="{ active: shipForm.express_id === e.id }" @click="selectExpress(e)"> {{e.name}} <uv-icon v-if="shipForm.express_id === e.id" name="checkmark" color="#0D69EF" size="32rpx"></uv-icon> </view> <view class="type-sheet-cancel" @click="showExpressPicker = false">取消</view> </view> <!-- 物流弹窗 --> <uv-popup ref="logisticsPopup" mode="bottom" round="20rpx" :safeAreaInsetBottom="true"> <view class="cancel-popup"> <view class="cancel-popup-header"> <view> <text class="cancel-popup-title">查看物流</text> <text class="cancel-popup-no" v-if="logisticsPackages.length">共 {{logisticsPackages.length}} 个包裹</text> </view> <uv-icon name="close" size="36rpx" color="#999" @click="logisticsPopup.close()"></uv-icon> </view> <!-- 多包裹切换 --> <scroll-view v-if="logisticsPackages.length > 1" scroll-x class="pkg-scroll"> <view class="pkg-list"> <view v-for="(pkg, pi) in logisticsPackages" :key="pi" class="pkg-card" :class="{ active: logisticsPkgIndex === pi }" @click="selectPackage(pi)"> <text class="pkg-company">{{pkg.express_company_name}}</text> <text class="pkg-no">{{pkg.express_code}}</text> <text class="pkg-time" v-if="pkg.shipping_time">{{pkg.shipping_time}}</text> </view> </view> </scroll-view> <!-- 单包裹信息头 --> <view v-else-if="logisticsPackages.length === 1" class="single-pkg-info"> <text class="single-pkg-company">{{logisticsPackages[0].express_company_name}}</text> <text class="single-pkg-no">{{logisticsPackages[0].express_code}}</text> </view> <scroll-view scroll-y style="max-height: 55vh;"> <view v-if="logisticsLoading" class="loading-row"> <uv-loading-icon mode="circle" size="40rpx"></uv-loading-icon> </view> <view v-else-if="currentTrack && currentTrack.data && currentTrack.data.length"> <view class="logistics-list"> <view class="logistics-item" v-for="(item, i) in currentTrack.data" :key="i" :class="{ first: i === 0 }"> <view class="logistics-dot-wrap"> <view class="logistics-dot" :class="{ active: i === 0 }"></view> <view class="logistics-line" v-if="i < currentTrack.data.length - 1"></view> </view> <view class="logistics-content"> <text class="logistics-time">{{item.time || item.ftime}}</text> <text class="logistics-context">{{item.context}}</text> </view> </view> </view> </view> <view v-else class="logistics-empty"> <view v-if="currentTrack"> <text class="logistics-no">快递单号:{{currentTrack.nu}}</text> <text class="logistics-company">快递公司:{{currentTrack.company}}</text> <text class="logistics-msg">{{currentTrack.message || '暂无物流信息'}}</text> </view> <uv-empty v-else-if="!logisticsLoading" mode="search" text="暂无物流信息" iconSize="120rpx"></uv-empty> </view> </scroll-view> </view> </uv-popup> <!-- 售后操作 sheet --> <view class="type-mask" v-if="showAfterSaleSheet" @click="showAfterSaleSheet=false"></view> <view class="type-sheet" :class="{ show: showAfterSaleSheet }"> <view class="type-sheet-title">售后操作</view> <view class="type-sheet-item" @click="doAfterSale('refundWithReturn')">退货退款</view> <view class="type-sheet-item" @click="doAfterSale('refundOnly')">仅退款</view> <view class="type-sheet-item" @click="doAfterSale('exchange')">换货</view> <view class="type-sheet-cancel" @click="showAfterSaleSheet=false">取消</view> </view> <!-- 取消订单弹窗 --> <uv-popup ref="cancelPopup" mode="bottom" round="20rpx" :safeAreaInsetBottom="true"> <view class="cancel-popup"> <view class="cancel-popup-header"> <view> <text class="cancel-popup-title">取消订单商品</text> <text class="cancel-popup-no">{{cancelOrder && cancelOrder.order_id}}</text> </view> <uv-icon name="close" size="36rpx" color="#999" @click="cancelPopup.close()"></uv-icon> </view> <scroll-view scroll-y style="max-height: 55vh;"> <view class="cancel-goods-list"> <view v-for="g in cancelGoodsList" :key="g.id" class="cancel-goods-item" :class="{ selected: cancelSelectedIds.includes(g.id), disabled: g.status === 2 }" @click="g.status !== 2 && toggleCancelGoods(g.id)"> <view class="check-box" :class="{ checked: cancelSelectedIds.includes(g.id) }"> <uv-icon v-if="cancelSelectedIds.includes(g.id)" name="checkmark" size="22rpx" color="#fff"></uv-icon> </view> <uv-image :src="g.goods_image" width="96rpx" height="96rpx" radius="8rpx" mode="aspectFill" style="flex-shrink:0"></uv-image> <view class="cancel-goods-info"> <view class="cancel-goods-name-row"> <text class="cancel-goods-name">{{g.goods_name}}</text> <text v-if="g.status === 2" class="cancelled-tag">已取消</text> </view> <text class="cancel-goods-spec" v-if="g.spec_data && Object.keys(g.spec_data).length"> {{Object.entries(g.spec_data).map(([k,v])=>k+':'+v).join(' ')}} </text> <view class="cancel-goods-price-row"> <text class="cancel-goods-price">¥{{g.goods_price}}</text> <text class="cancel-goods-qty">x{{g.goods_num}}</text> </view> </view> </view> </view> </scroll-view> <view class="cancel-popup-footer"> <text class="cancel-selected-tip" v-if="cancelSelectedIds.length">已选 {{cancelSelectedIds.length}} 件</text> <text class="cancel-selected-tip" v-else>请选择要取消的商品</text> <view class="cancel-confirm-btn" :class="{ disabled: !cancelSelectedIds.length }" @click="confirmCancelOrder"> 确认取消 </view> </view> </view> </uv-popup> </view> </template> <script> import allConfig from "@/utils/config.js" export default { data() { return { keyword: '', searchType: 'order_no', showTypePicker: false, searchTypes: [ { label: '订单号', key: 'order_no' }, { label: '客户姓名', key: 'nickname' }, { label: '手机号', key: 'mobile' }, { label: '商品名称', key: 'goods_name' }, ], orderList: [], page: 1, total: 0, loading: false, refreshing: false, noMore: false, currentStatus: -1, shipPopup: null, shipOrder: null, shipMode: 1, shipGoodsList: [], shipping: false, shipForm: { express_id: null, express_name: '', express_no: '', remark: '' }, expressList: [], expressLoading: false, showExpressPicker: false, logisticsPopup: null, logisticsPackages: [], logisticsPkgIndex: 0, currentTrack: null, logisticsLoading: false, showAfterSaleSheet: false, afterSaleOrder: null, cancelPopup: null, cancelOrder: null, cancelGoodsList: [], cancelSelectedIds: [], tabList: [ { name: '全部', status: -1, countKey: 'total', count: 0 }, { name: '待到货', status: 1, countKey: 'pending', count: 0 }, { name: '待补款', status: 2, countKey: 'unpaid', count: 0 }, { name: '待发货', status: 3, countKey: 'unshipped', count: 0 }, { name: '已发货', status: 4, countKey: 'shipped', count: 0 }, { name: '售后中', status: 5, countKey: 'aftersale', count: 0 }, { name: '已完成', status: 6, countKey: 'completed', count: 0 }, { name: '已退款', status: 7, countKey: 'refunded', count: 0 }, { name: '已取消', status: 8, countKey: 'cancelled', count: 0 }, { name: '已报损', status: 9, countKey: 'damaged', count: 0 }, { name: '售后记录',status: 10, countKey: 'sales', count: 0 }, { name: '售后订单',status: 11, countKey: 'sale', count: 0 }, ], statusMap: { 1:'待到货', 2:'待补款', 3:'待发货', 4:'已发货', 5:'售后中', 6:'已完成', 7:'已退款', 8:'已取消', 9:'已报损', 10:'售后记录', 11:'售后订单' }, orderTypeMap: { 1:'正常订单', 2:'售后订单', 3:'换货订单' }, CANCEL_ROLES: ['superAdmin', 'admin', 'dzAdmin', 'cw', 'hg'], AFTERSALE_ROLES: ['superAdmin', 'admin', 'dzAdmin', 'cw'], AUDIT_ROLES: ['superAdmin', 'admin', 'cw', 'ckxd', 'hg', 'sy', 'shsh'], } }, computed: { currentTypeLabel() { const t = this.searchTypes.find(item => item.key === this.searchType) return t ? t.label : '订单号' }, currentPlaceholder() { return `请输入${this.currentTypeLabel}` }, tabListDisplay() { return this.tabList.map(t => ({ ...t, name: `${t.name}(${t.count})` })) }, canSplitShip() { const list = this.shipOrder?.goods_list || [] const available = list.filter(g => g.status !== 2) if (available.length === 0) return false if (available.length === 1 && available[0].goods_num === 1) return false return true }, }, onShow() { this.fetchStatusCount() this.resetAndLoad() }, methods: { baseUrl(path) { // #ifdef APP-PLUS||MP-WEIXIN return allConfig + path // #endif return path }, formatSpec(specData) { if (!specData || typeof specData !== 'object') return '' if (Array.isArray(specData)) return '' return Object.entries(specData).map(([k, v]) => `${k}:${v}`).join(' ') }, hasPartialCancelled(goodsList) { if (!goodsList || !goodsList.length) return false const cancelledCount = goodsList.filter(g => g.status === 2).length return cancelledCount > 0 && cancelledCount < goodsList.length }, onSelectType(t) { this.searchType = t.key this.keyword = '' this.showTypePicker = false }, onSearch() { this.resetAndLoad() }, onRefresh() { this.refreshing = true this.resetAndLoad() }, loadMore() { if (this.noMore || this.loading) return this.page++ this.fetchOrders() }, changeTab(e) { this.currentStatus = this.tabList[e.index].status this.resetAndLoad() }, goDetail(order) { uni.navigateTo({ url: `/pagesA/order/order-details?id=${order.id}` }) }, resetAndLoad() { this.page = 1 this.noMore = false this.orderList = [] this.fetchOrders() }, fetchStatusCount() { const token = uni.getStorageSync('TOKEN') uni.request({ url: this.baseUrl('/prod/admin/order/Orders/statusCount'), method: 'POST', header: { 'authori-zation': token }, success: (res) => { if (res.data.code === 200) { const d = res.data.data this.tabList.forEach(tab => { tab.count = d[tab.countKey] ?? 0 }) } } }) }, fetchOrders() { if (this.loading) return this.loading = true const token = uni.getStorageSync('TOKEN') let url = this.baseUrl('/prod/admin/order/Orders/index') url += `?page=${this.page}&limit=10&orderBy=id&orderType=desc` url += `&order_status=${this.currentStatus}` if (this.keyword) url += `&${this.searchType}=${encodeURIComponent(this.keyword)}` uni.request({ url, method: 'GET', header: { 'authori-zation': token }, success: (res) => { if (res.data.code === 200) { const d = res.data.data const list = d.data || [] this.total = d.total || 0 this.orderList = this.page === 1 ? list : [...this.orderList, ...list] this.noMore = this.orderList.length >= this.total } }, complete: () => { this.loading = false; this.refreshing = false } }) }, getUserRoles() { const info = uni.getStorageSync('userInfo') if (!info) return [] const roleList = info.roleList || [] return roleList.map(r => r.code || r.name || r) }, hasRole(roles) { const userRoles = this.getUserRoles() if (!userRoles.length) return false return roles.some(r => userRoles.includes(r)) }, getActions(order) { const s = order.order_status const actions = [] actions.push({ label: '详情', type: 'outline', action: 'detail' }) if (s === 1) { actions.push({ label: '立即补款', type: 'primary', action: 'payment' }) actions.push({ label: '预售退款', type: 'outline', action: 'presaleRefund' }) actions.push({ label: '信息修改', type: 'outline', action: 'edit' }) if (this.hasRole(this.CANCEL_ROLES)) actions.push({ label: '取消订单', type: 'danger', action: 'cancel' }) } else if (s === 2) { actions.push({ label: '立即补款', type: 'primary', action: 'payment' }) actions.push({ label: '信息修改', type: 'outline', action: 'edit' }) if (this.hasRole(this.CANCEL_ROLES)) actions.push({ label: '取消订单', type: 'danger', action: 'cancel' }) } else if (s === 3) { actions.push({ label: '信息修改', type: 'outline', action: 'edit' }) if (this.hasRole(this.CANCEL_ROLES)) actions.push({ label: '取消订单', type: 'danger', action: 'cancel' }) actions.push({ label: '立即发货', type: 'primary', action: 'ship' }) } else if (s === 4) { actions.push({ label: '查看物流', type: 'outline', action: 'logistics' }) actions.push({ label: '确认收货', type: 'outline', action: 'confirmReceipt' }) if (this.hasRole(this.AFTERSALE_ROLES)) { actions.push({ label: '售后操作', type: 'outline', action: 'afterSale' }) } } else if (s === 5) { actions.push({ label: '查看物流', type: 'outline', action: 'logistics' }) if (this.hasRole(this.AUDIT_ROLES)) actions.push({ label: '审核售后', type: 'primary', action: 'auditAfterSale' }) } else if (s === 6) { actions.push({ label: '售后操作', type: 'outline', action: 'afterSale' }) } return actions }, handleAction(act, order) { if (act.action === 'detail') { uni.navigateTo({ url: `/pagesA/order/order-details?id=${order.id}` }) } else if (act.action === 'ship') { this.openShipPopup(order) } else if (act.action === 'cancel') { this.cancelOrder = order this.cancelGoodsList = order.goods_list || [] this.cancelSelectedIds = [] this.cancelPopup.open() } else if (act.action === 'edit') { uni.navigateTo({ url: `/pagesA/order/order-edit?id=${order.id}` }) } else if (act.action === 'payment') { uni.navigateTo({ url: `/pagesA/order/order-payment?id=${order.id}` }) } else if (act.action === 'presaleRefund') { uni.navigateTo({ url: `/pagesA/order/presale-refund?id=${order.id}` }) } else if (act.action === 'logistics') { this.openLogisticsPopup(order) } else if (act.action === 'confirmReceipt') { uni.showModal({ title: '确认收货', content: `确认订单 ${order.order_id} 已收货?`, success: (res) => { if (res.confirm) this.doConfirmReceipt(order) } }) } else if (act.action === 'refundWithReturn') { uni.navigateTo({ url: `/pagesA/order/after-sale?id=${order.id}&type=refundWithReturn` }) } else if (act.action === 'refundOnly') { uni.navigateTo({ url: `/pagesA/order/after-sale?id=${order.id}&type=refundOnly` }) } else if (act.action === 'exchange') { uni.navigateTo({ url: `/pagesA/order/after-sale?id=${order.id}&type=exchange` }) } else if (act.action === 'auditAfterSale') { uni.navigateTo({ url: `/pagesA/order/after-sale-audit?id=${order.id}` }) } }, doConfirmReceipt(order) { const token = uni.getStorageSync('TOKEN') uni.request({ url: this.baseUrl(`/prod/admin/order/Orders/update?id=${order.id}`), method: 'PUT', header: { 'authori-zation': token, 'content-type': 'application/json' }, data: { order_status: 6 }, success: (res) => { if (res.data.code === 200) { uni.showToast({ title: '确认收货成功', icon: 'success' }) this.resetAndLoad() } else { uni.showToast({ title: res.data.message || '操作失败', icon: 'none' }) } } }) }, getShippedQty(g, shippingInfoItem) { if (!shippingInfoItem) return 0 return shippingInfoItem .filter(s => s.order_item_id === g.id) .reduce((sum, s) => sum + (s.shipped_quantity || 0), 0) }, fetchExpressList() { if (this.expressList.length) return this.expressLoading = true const token = uni.getStorageSync('TOKEN') uni.request({ url: this.baseUrl('/prod/admin/setting/ExpressCompany/index?page=1&pageSize=100'), method: 'GET', header: { 'authori-zation': token }, success: (res) => { if (res.data.code === 200) this.expressList = res.data.data.data || [] }, complete: () => { this.expressLoading = false } }) }, selectExpress(e) { this.shipForm.express_id = e.id this.shipForm.express_name = e.name this.showExpressPicker = false }, setShipMode(mode) { this.shipMode = mode this.shipGoodsList.forEach(g => { g._selected = false; g.ship_qty = 1 }) }, openShipPopup(order) { this.shipOrder = order this.shipMode = 1 this.shipForm = { express_id: null, express_name: '', express_no: '', remark: '' } this.fetchExpressList() const infoItem = order.shipping_info_item || [] this.shipGoodsList = (order.goods_list || []).map(g => { const shipped = this.getShippedQty(g, infoItem) const available = Math.max(0, g.goods_num - shipped) return { ...g, _selected: false, ship_qty: Math.min(1, available), _shippedQty: shipped, _availableQty: available } }) this.shipPopup.open() }, confirmShip() { if (!this.shipForm.express_name) return uni.showToast({ title: '请选择快递公司', icon: 'none' }) if (!this.shipForm.express_no.trim()) return uni.showToast({ title: '请输入快递单号', icon: 'none' }) if (this.shipMode === 2) { const selected = this.shipGoodsList.filter(g => g._selected) if (!selected.length) return uni.showToast({ title: '请选择要发货的商品', icon: 'none' }) } this.shipping = true const token = uni.getStorageSync('TOKEN') const data = { id: this.shipOrder.id, express_company_id: this.shipForm.express_id, express_company_name: this.shipForm.express_name, express_code: this.shipForm.express_no, remark: this.shipForm.remark, shipping_mode: this.shipMode, shipping_type: 1, } if (this.shipMode === 2) { data.selected_goods = this.shipGoodsList .filter(g => g._selected) .map(g => ({ goods_id: g.goods_id, order_item_id: g.id, shipping_qty: g.ship_qty })) } uni.request({ url: this.baseUrl('/prod/admin/order/Orders/ship'), method: 'POST', header: { 'authori-zation': token, 'content-type': 'application/json' }, data, success: (res) => { if (res.data.code === 200) { uni.showToast({ title: '发货成功', icon: 'success' }) this.shipPopup.close() this.resetAndLoad() } else { uni.showToast({ title: res.data.message || '操作失败', icon: 'none' }) } }, fail: () => uni.showToast({ title: '网络错误', icon: 'none' }), complete: () => { this.shipping = false } }) }, openLogisticsPopup(order) { const pkgs = order.shipping_info || [] this.logisticsPackages = pkgs this.logisticsPkgIndex = 0 this.currentTrack = null this.logisticsPopup.open() if (pkgs.length > 0) { this.loadPackageTracks(0) } }, selectPackage(index) { if (this.logisticsPkgIndex === index) return this.logisticsPkgIndex = index this.currentTrack = null this.loadPackageTracks(index) }, loadPackageTracks(index) { const pkg = this.logisticsPackages[index] if (!pkg) return this.logisticsLoading = true const token = uni.getStorageSync('TOKEN') uni.request({ url: this.baseUrl(`/prod/admin/order/Orders/shippingInfo?order_id=${pkg.id}`), method: 'GET', header: { 'authori-zation': token }, success: (res) => { if (res.data.code === 200) { this.currentTrack = res.data.data } else { uni.showToast({ title: res.data.message || '获取失败', icon: 'none' }) } }, fail: () => uni.showToast({ title: '网络错误', icon: 'none' }), complete: () => { this.logisticsLoading = false } }) }, openAfterSaleSheet(order) { this.afterSaleOrder = order this.showAfterSaleSheet = true }, doAfterSale(type) { this.showAfterSaleSheet = false const order = this.afterSaleOrder if (!order) return uni.navigateTo({ url: `/pagesA/order/after-sale?id=${order.id}&type=${type}` }) }, toggleCancelGoods(id) { const idx = this.cancelSelectedIds.indexOf(id) if (idx > -1) this.cancelSelectedIds.splice(idx, 1) else this.cancelSelectedIds.push(id) }, confirmCancelOrder() { if (!this.cancelSelectedIds.length) return uni.showToast({ title: '请选择要取消的商品', icon: 'none' }) uni.showModal({ title: '确认取消', content: `确认取消选中的 ${this.cancelSelectedIds.length} 件商品?`, success: (res) => { if (!res.confirm) return const token = uni.getStorageSync('TOKEN') uni.request({ url: this.baseUrl('/prod/admin/order/Orders/cancelOrder'), method: 'POST', header: { 'authori-zation': token, 'content-type': 'application/json' }, data: { order_id: this.cancelOrder.id, goods_ids: this.cancelSelectedIds, }, success: (r) => { if (r.data.code === 200) { uni.showToast({ title: '取消成功', icon: 'success' }) this.cancelPopup.close() this.resetAndLoad() } else { uni.showToast({ title: r.data.message || '操作失败', icon: 'none' }) } }, fail: () => uni.showToast({ title: '网络错误', icon: 'none' }) }) } }) }, } } </script> <style lang="scss" scoped> page { background: #f7f8f8; } .content { height: 100vh; display: flex; flex-direction: column; } .search-box { padding: 16rpx 24rpx; background: #fff; .search-row { display: flex; align-items: center; background: #f7f8f8; border-radius: 12rpx; overflow: hidden; height: 80rpx; } .search-select { display: flex; align-items: center; gap: 8rpx; padding: 0 20rpx; height: 100%; white-space: nowrap; font-size: 26rpx; color: #333; border-right: 1rpx solid #e5e5e5; flex-shrink: 0; } .search-input { flex: 1; height: 100%; padding: 0 16rpx; font-size: 26rpx; color: #1a1a1a; background: transparent; } .search-btn { padding: 0 28rpx; height: 100%; background: #0D69EF; color: #fff; font-size: 26rpx; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } } .order-scroll { flex: 1; overflow: hidden; } .order-list { padding: 0 24rpx; } .order-card { background: #fff; border-radius: 16rpx; margin-top: 20rpx; overflow: hidden; .order-head { display: flex; align-items: center; justify-content: space-between; padding: 20rpx 24rpx; border-bottom: 1rpx solid #f5f5f5; .order-head-left { display: flex; align-items: center; gap: 16rpx; } .order-member { font-size: 28rpx; font-weight: 600; color: #1a1a1a; } .order-store { font-size: 22rpx; color: #999; } } .order-no-row { display: flex; align-items: center; gap: 16rpx; padding: 12rpx 24rpx; border-bottom: 1rpx solid #f9f9f9; .order-no { font-size: 22rpx; color: #999; flex: 1; } .order-type-tag { font-size: 20rpx; padding: 4rpx 12rpx; border-radius: 6rpx; color: #0D69EF; background: rgba(13,105,239,0.08); } .partial-cancel-tag { font-size: 20rpx; padding: 4rpx 12rpx; border-radius: 6rpx; color: #ff7a00; background: rgba(255,122,0,0.1); } .partial-ship-tag { font-size: 20rpx; padding: 4rpx 12rpx; border-radius: 6rpx; color: #f53f3f; background: rgba(245,63,63,0.1); } } .goods-row { display: flex; gap: 20rpx; padding: 20rpx 24rpx; border-bottom: 1rpx solid #f9f9f9; .goods-info { flex: 1; display: flex; flex-direction: column; gap: 8rpx; } .goods-name { font-size: 26rpx; color: #333; } .goods-spec { font-size: 22rpx; color: #999; } .goods-price-row { display: flex; align-items: center; justify-content: space-between; } .goods-price { font-size: 26rpx; font-weight: 600; color: #333; } .goods-num { font-size: 24rpx; color: #999; } } .more-goods { padding: 8rpx 24rpx; font-size: 22rpx; color: #999; border-bottom: 1rpx solid #f9f9f9; } .order-foot { display: flex; align-items: center; justify-content: space-between; padding: 16rpx 24rpx; background: #fafafa; .order-time { font-size: 22rpx; color: #999; } .order-amount { display: flex; align-items: baseline; gap: 6rpx; } .amount-label { font-size: 22rpx; color: #999; } .amount-val { font-size: 30rpx; font-weight: 700; color: #1a1a1a; } } .order-actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 12rpx; padding: 16rpx 24rpx; border-top: 1rpx solid #f5f5f5; .action-btn { font-size: 24rpx; padding: 10rpx 24rpx; border-radius: 40rpx; white-space: nowrap; flex-shrink: 0; display: flex; align-items: center; &.primary { color: #0D69EF; border: 1rpx solid #0D69EF; } &.outline { color: #666; border: 1rpx solid #ccc; } &.danger { color: #F56C6C; border: 1rpx solid #F56C6C; } } } } .order-status-tag { font-size: 22rpx; padding: 4rpx 14rpx; border-radius: 20rpx; &.s1 { color: #F7A600; background: rgba(247,166,0,0.1); } // 待到货 &.s2 { color: #F7A600; background: rgba(247,166,0,0.1); } // 待补款 &.s3 { color: #F56C6C; background: rgba(245,108,108,0.1); } // 售后订单 &.s4 { color: #0D69EF; background: rgba(13,105,239,0.1); } // 待发货 &.s5 { color: #0D69EF; background: rgba(13,105,239,0.1); } // 已发货 &.s6 { color: #F56C6C; background: rgba(245,108,108,0.1); } // 售后中 &.s7 { color: #0EB836; background: rgba(14,184,54,0.1); } // 已完成 &.s8 { color: #999; background: #f5f5f5; } // 已退款 &.s9 { color: #999; background: #f5f5f5; } // 已取消 &.s10 { color: #999; background: #f5f5f5; } // 已报损 &.s11 { color: #F56C6C; background: rgba(245,108,108,0.1); } // 售后记录 } .load-tip { text-align: center; padding: 20rpx 0 40rpx; font-size: 24rpx; color: #999; } .empty-box { padding-top: 200rpx; } .tab-item { display: flex; align-items: baseline; gap: 4rpx; white-space: nowrap; .tab-count { font-size: 20rpx; color: #999; } } .ship-popup { background: #fff; padding-bottom: env(safe-area-inset-bottom); } .ship-popup-header { display: flex; align-items: flex-start; justify-content: space-between; padding: 32rpx 32rpx 20rpx; border-bottom: 1rpx solid #f0f0f0; .ship-popup-title { font-size: 30rpx; font-weight: 600; color: #1a1a1a; display: block; margin-bottom: 6rpx; } .ship-popup-no { font-size: 22rpx; color: #999; display: block; } } .ship-mode-row { display: flex; gap: 24rpx; padding: 20rpx 32rpx; border-bottom: 1rpx solid #f5f5f5; .ship-mode-item { display: flex; align-items: center; gap: 10rpx; font-size: 28rpx; color: #333; &.active { color: #0D69EF; font-weight: 600; } &.disabled { color: #ccc; } } .ship-mode-dot { width: 32rpx; height: 32rpx; border-radius: 50%; border: 2rpx solid #ccc; background: #fff; flex-shrink: 0; display: flex; align-items: center; justify-content: center; &.active { border-color: #0D69EF; background: #0D69EF; } &.active::after { content: ''; width: 14rpx; height: 14rpx; border-radius: 50%; background: #fff; } } } /* 整单商品预览 */ .whole-goods-section { padding: 16rpx 32rpx 0; } .whole-goods-item { display: flex; align-items: center; gap: 16rpx; padding: 16rpx 0; border-bottom: 1rpx solid #f5f5f5; &:last-child { border-bottom: none; } &.cancelled { opacity: 0.45; } &.shipped { opacity: 0.55; } .whole-goods-info { flex: 1; display: flex; flex-direction: column; gap: 6rpx; } .whole-goods-name-row { display: flex; align-items: center; gap: 10rpx; } .whole-goods-name { font-size: 26rpx; color: #1a1a1a; font-weight: 500; flex: 1; } .whole-goods-spec { font-size: 22rpx; color: #999; } .whole-goods-price-row { display: flex; align-items: center; gap: 12rpx; } .whole-goods-price { font-size: 26rpx; color: #F56C6C; font-weight: 600; } .whole-goods-qty { font-size: 22rpx; color: #bbb; } .whole-goods-shipped { font-size: 22rpx; color: #0EB836; margin-left: auto; } } /* 分单商品选择 */ .split-goods-section { padding: 16rpx 24rpx 0; } .split-tip { font-size: 24rpx; color: #999; margin-bottom: 12rpx; padding: 0 8rpx; } .split-goods-item { display: flex; align-items: flex-start; gap: 16rpx; padding: 20rpx; margin-bottom: 16rpx; border-radius: 14rpx; border: 2rpx solid #f0f0f0; background: #fafafa; &.selected { border-color: #0D69EF; background: rgba(13,105,239,0.04); } &.disabled { opacity: 0.45; } .check-box { width: 40rpx; height: 40rpx; border-radius: 8rpx; flex-shrink: 0; margin-top: 4rpx; border: 2rpx solid #ddd; background: #fff; display: flex; align-items: center; justify-content: center; &.checked { background: #0D69EF; border-color: #0D69EF; } } .split-goods-info { flex: 1; display: flex; flex-direction: column; gap: 8rpx; } .split-goods-name-row { display: flex; align-items: center; gap: 10rpx; flex-wrap: wrap; } .split-goods-name { font-size: 26rpx; font-weight: 500; color: #1a1a1a; flex: 1; } .split-goods-spec { font-size: 22rpx; color: #999; } .split-goods-qty-row { display: flex; align-items: center; gap: 16rpx; } .split-qty-label { font-size: 24rpx; color: #555; } .qty-ctrl { display: flex; align-items: center; gap: 12rpx; } .qty-btn { width: 48rpx; height: 48rpx; background: #f0f0f0; border-radius: 8rpx; display: flex; align-items: center; justify-content: center; font-size: 28rpx; color: #444; } .qty-num { font-size: 28rpx; font-weight: 600; color: #1a1a1a; min-width: 32rpx; text-align: center; } .qty-hint { font-size: 22rpx; color: #999; } } /* 快递表单 */ .ship-form-section { padding: 20rpx 32rpx 0; } .ship-form-item { display: flex; align-items: center; padding: 24rpx 0; border-bottom: 1rpx solid #f5f5f5; &:last-child { border-bottom: none; } .ship-form-label { font-size: 28rpx; color: #333; width: 160rpx; flex-shrink: 0; .req { color: #F56C6C; } } .ship-form-input { flex: 1; font-size: 28rpx; color: #1a1a1a; } .ship-form-input-row { flex: 1; display: flex; align-items: center; justify-content: flex-end; gap: 8rpx; } .ship-form-val { font-size: 28rpx; color: #1a1a1a; text-align: right; } .ship-form-placeholder { font-size: 28rpx; color: #c0c0c0; text-align: right; } } .type-sheet-loading { display: flex; justify-content: center; padding: 40rpx; } /* 底部按钮 */ .ship-popup-footer { display: flex; gap: 20rpx; padding: 20rpx 32rpx 32rpx; border-top: 1rpx solid #f0f0f0; .ship-cancel-btn { flex: 1; height: 88rpx; border-radius: 44rpx; background: #f5f5f5; color: #666; display: flex; align-items: center; justify-content: center; font-size: 30rpx; } .ship-confirm-btn { flex: 2; height: 88rpx; border-radius: 44rpx; background: linear-gradient(135deg, #1a7aff, #0D69EF); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 30rpx; font-weight: 600; box-shadow: 0 4rpx 16rpx rgba(13,105,239,0.3); &.loading { background: #a0c4ff; box-shadow: none; } } } /* 状态标签 */ .tag-cancelled { font-size: 20rpx; color: #fff; background: #bbb; padding: 2rpx 10rpx; border-radius: 6rpx; flex-shrink: 0; } .tag-shipped { font-size: 20rpx; color: #fff; background: #0EB836; padding: 2rpx 10rpx; border-radius: 6rpx; flex-shrink: 0; } .tag-partial { font-size: 20rpx; color: #fff; background: #ff7a00; padding: 2rpx 10rpx; border-radius: 6rpx; flex-shrink: 0; } /* 取消订单商品列表 */ .cancel-popup { background: #fff; padding-bottom: env(safe-area-inset-bottom); } .cancel-popup-header { display: flex; align-items: flex-start; justify-content: space-between; padding: 32rpx 32rpx 20rpx; border-bottom: 1rpx solid #f0f0f0; .cancel-popup-title { font-size: 30rpx; font-weight: 600; color: #1a1a1a; display: block; margin-bottom: 6rpx; } .cancel-popup-no { font-size: 22rpx; color: #999; display: block; } } .cancel-goods-list { padding: 16rpx 24rpx 8rpx; } .cancel-goods-item { display: flex; align-items: center; gap: 16rpx; padding: 20rpx; margin-bottom: 16rpx; border-radius: 14rpx; border: 2rpx solid #f0f0f0; background: #fafafa; transition: all 0.15s; &.selected { border-color: #0D69EF; background: rgba(13,105,239,0.04); } &.disabled { opacity: 0.45; } .check-box { width: 40rpx; height: 40rpx; border-radius: 8rpx; flex-shrink: 0; border: 2rpx solid #ddd; background: #fff; display: flex; align-items: center; justify-content: center; &.checked { background: #0D69EF; border-color: #0D69EF; } } .cancel-goods-info { flex: 1; display: flex; flex-direction: column; gap: 6rpx; overflow: hidden; } .cancel-goods-name-row { display: flex; align-items: center; gap: 10rpx; flex-wrap: wrap; } .cancel-goods-name { font-size: 26rpx; font-weight: 500; color: #1a1a1a; line-height: 1.4; flex: 1; } .cancelled-tag { font-size: 20rpx; color: #fff; background: #bbb; padding: 2rpx 10rpx; border-radius: 6rpx; flex-shrink: 0; } .cancel-goods-spec { font-size: 22rpx; color: #999; } .cancel-goods-price-row { display: flex; align-items: center; gap: 12rpx; } .cancel-goods-price { font-size: 26rpx; color: #F56C6C; font-weight: 600; } .cancel-goods-qty { font-size: 22rpx; color: #bbb; } } .cancel-popup-footer { display: flex; align-items: center; justify-content: space-between; padding: 20rpx 32rpx 32rpx; border-top: 1rpx solid #f0f0f0; .cancel-selected-tip { font-size: 26rpx; color: #999; } .cancel-confirm-btn { background: #F56C6C; color: #fff; height: 80rpx; padding: 0 48rpx; border-radius: 40rpx; display: flex; align-items: center; justify-content: center; font-size: 28rpx; font-weight: 500; &.disabled { background: #ddd; color: #bbb; } } } /* 物流 */ .loading-row { display: flex; align-items: center; justify-content: center; padding: 60rpx; } .pkg-scroll { border-bottom: 1rpx solid #f0f0f0; } .pkg-list { display: flex; gap: 16rpx; padding: 20rpx 24rpx; white-space: nowrap; } .pkg-card { display: inline-flex; flex-direction: column; gap: 6rpx; padding: 16rpx 24rpx; border-radius: 12rpx; border: 2rpx solid #eee; background: #fafafa; flex-shrink: 0; &.active { border-color: #0D69EF; background: rgba(13,105,239,0.05); } .pkg-company { font-size: 24rpx; color: #333; font-weight: 500; } .pkg-no { font-size: 22rpx; color: #999; } .pkg-time { font-size: 20rpx; color: #bbb; } } .single-pkg-info { display: flex; align-items: center; gap: 16rpx; padding: 16rpx 32rpx; border-bottom: 1rpx solid #f0f0f0; .single-pkg-company { font-size: 26rpx; color: #333; font-weight: 500; } .single-pkg-no { font-size: 24rpx; color: #999; } } .logistics-list { padding: 24rpx 32rpx; } .logistics-item { display: flex; gap: 20rpx; padding-bottom: 32rpx; .logistics-dot-wrap { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; } .logistics-dot { width: 20rpx; height: 20rpx; border-radius: 50%; background: #ccc; flex-shrink: 0; margin-top: 6rpx; } .logistics-line { flex: 1; width: 2rpx; background: #eee; margin-top: 8rpx; min-height: 40rpx; } .logistics-content { flex: 1; display: flex; flex-direction: column; gap: 8rpx; } .logistics-time { font-size: 22rpx; color: #999; } .logistics-context { font-size: 26rpx; color: #333; line-height: 1.6; } &.first .logistics-dot { background: #0D69EF; } &.first .logistics-content { color: #1a1a1a; font-weight: 500; } } .logistics-empty { padding: 40rpx 32rpx; display: flex; flex-direction: column; gap: 16rpx; .logistics-no, .logistics-company { font-size: 26rpx; color: #555; } .logistics-msg { font-size: 26rpx; color: #999; margin-top: 8rpx; } } .type-mask { position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 9998; } .type-sheet { position: fixed; bottom: 0; left: 0; width: 100%; background: #fff; border-radius: 24rpx 24rpx 0 0; z-index: 9999; padding-bottom: env(safe-area-inset-bottom); transform: translateY(100%); transition: transform 0.25s ease; &.show { transform: translateY(0); } .type-sheet-title { text-align: center; font-size: 28rpx; color: #999; padding: 28rpx 0 16rpx; border-bottom: 1rpx solid #f5f5f5; } .type-sheet-item { display: flex; align-items: center; justify-content: space-between; padding: 32rpx 48rpx; font-size: 30rpx; color: #1a1a1a; border-bottom: 1rpx solid #f9f9f9; &.active { color: #0D69EF; font-weight: 600; } } .type-sheet-cancel { text-align: center; padding: 32rpx; font-size: 30rpx; color: #999; } } </style>
errMsg: "getLocation:fail timeout"
微信开发者助手
帮助小程序相关成员在手机端更方便、及时地管理小程序
微信开发者助手
扫码体验