diff --git a/.crmeb/skills/crmeb-dev/references/05-用户端开发/user-order-detail.md b/.crmeb/skills/crmeb-dev/references/05-用户端开发/user-order-detail.md index 75365a03b..c73a04d4f 100644 --- a/.crmeb/skills/crmeb-dev/references/05-用户端开发/user-order-detail.md +++ b/.crmeb/skills/crmeb-dev/references/05-用户端开发/user-order-detail.md @@ -497,7 +497,7 @@ GET /api/center/order/detail/{orderNo} "invoice": { // 发票信息(order_center.invoice 为空时从 eb_store_order_invoice 查询) "title": "公司名称", // 发票抬头名称 "header_type": 2, // 1=个人 2=企业 - "type": 1, // 1=电子发票 2=纸质发票 + "type": 1, // 1=普通发票 2=专用发票 "tax_number": "91110000MA00XXXXXX", // 税号(企业抬头才有) "email": "test@example.com", // 接收邮箱 "phone": "13800138000", // 联系电话 diff --git a/backend/app/api/controller/v1/order/CenterOrderController.php b/backend/app/api/controller/v1/order/CenterOrderController.php index 65712a6cd..b127c0aa1 100644 --- a/backend/app/api/controller/v1/order/CenterOrderController.php +++ b/backend/app/api/controller/v1/order/CenterOrderController.php @@ -140,7 +140,7 @@ class CenterOrderController }) ); } - // 送礼订单按查看者裁剪:购买者隐藏收货信息/物流/相关按钮,领取人保留只读物流能力 + // 送礼订单按查看者裁剪:送礼人隐藏收货/物流/评价/售后,领取人保留收货物流与评价 $result = $services->applyGiftViewerPolicy($result, $uid); return app('json')->success($result); } catch (\Throwable $e) { @@ -282,6 +282,9 @@ class CenterOrderController 'door_service_postage' => $doorServicePostage, // 上门服务费用(元) 'remark' => true, // 买家留言,与配送方式无关 'invoice' => (bool)sys_config('invoice_func_status', 0), // 发票,与商品类型无关 + // 专用发票:须发票功能开启且专票开关开启 + 'special_invoice' => (bool)sys_config('invoice_func_status', 0) + && (bool)sys_config('special_invoice_status', 0), 'integral' => !$isActivityOrder && $integralOpen, // 积分抵扣,与商品类型无关 'coupon' => !$isActivityOrder && !empty($couponList), // 优惠券,与商品类型无关 'custom_form' => !empty($formattedCustomForm), // 自定义表单,与商品类型无关 @@ -557,6 +560,9 @@ class CenterOrderController 'door_service_postage' => $doorServicePostage, // 上门服务费用(元) 'remark' => true, // 买家留言 'invoice' => (bool)sys_config('invoice_func_status', 0),// 发票 + // 专用发票:须发票功能开启且专票开关开启 + 'special_invoice' => (bool)sys_config('invoice_func_status', 0) + && (bool)sys_config('special_invoice_status', 0), 'integral' => $integralOpen, // 积分抵扣 'coupon' => !empty($couponList), // 优惠券 'custom_form' => !empty($cartCustomForm), // 自定义表单(取主商品定义) diff --git a/backend/app/api/controller/v1/order/StoreOrderInvoiceController.php b/backend/app/api/controller/v1/order/StoreOrderInvoiceController.php index a926b5699..b47d92cef 100644 --- a/backend/app/api/controller/v1/order/StoreOrderInvoiceController.php +++ b/backend/app/api/controller/v1/order/StoreOrderInvoiceController.php @@ -86,29 +86,99 @@ class StoreOrderInvoiceController if ((int)($order['uid'] ?? 0) !== $uid) { return app('json')->fail('订单不存在'); } - // 本人开票记录 + // 本人开票记录(申请表为真源);无记录时回退下单快照 $orderInvoice = $this->services->getOne(['order_id' => (int)$order['id'], 'uid' => $uid]); - $order['invoice'] = $orderInvoice ? $orderInvoice->toArray() : []; + if ($orderInvoice) { + $invoice = $orderInvoice->toArray(); + } else { + $invoice = is_array($order['invoice'] ?? null) ? $order['invoice'] : []; + } + // 兼容旧页字段:备注列名、时间展示 + if ($invoice) { + if (!isset($invoice['remark']) && isset($invoice['invoice_reamrk'])) { + $invoice['remark'] = $invoice['invoice_reamrk']; + } + if (isset($invoice['add_time']) && is_numeric($invoice['add_time'])) { + $invoice['add_time'] = date('Y-m-d H:i:s', (int)$invoice['add_time']); + } + if (isset($invoice['invoice_time']) && is_numeric($invoice['invoice_time']) && (int)$invoice['invoice_time'] > 0) { + $invoice['invoice_time'] = date('Y-m-d H:i:s', (int)$invoice['invoice_time']); + } + } + $order['invoice'] = $invoice ?: []; + // 以下映射旧版发票详情页所需的订单字段(旧 eb_store_order 结构已由订单中台替代) $order['order_id'] = $order['order_no'] ?? $uni; - $order['add_time_y'] = date('Y-m-d', (int)($order['add_time'] ?? time())); - $order['add_time_h'] = date('H:i:s', (int)($order['add_time'] ?? time())); - $order['paid'] = (int)($order['pay_status'] ?? 0) == 1; + $addTime = (int)($order['add_time'] ?? time()); + $order['add_time_y'] = date('Y-m-d', $addTime); + $order['add_time_h'] = date('H:i:s', $addTime); + $payStatus = (int)($order['pay_status'] ?? 0); + $order['paid'] = in_array($payStatus, [1, 2], true) ? 1 : 0; + $legacyStatus = $this->services->statusToLegacy((string)($order['status_code'] ?? '')); + $order['status'] = $legacyStatus; $order['_status'] = [ - '_type' => $this->services->statusToLegacy($order['status_code'] ?? ''), - '_payType' => $order['pay_type_name'] ?? ($order['pay_type'] ?? ''), + '_type' => $legacyStatus, + '_payType' => (string)($order['pay_type_name'] ?? ($order['pay_type'] ?? '')), ]; - // 收货人信息优先取订单配送快照 - $contact = is_array($order['contact'] ?? null) ? $order['contact'] : []; - $order['real_name'] = $contact['name'] ?? ''; - $order['user_phone'] = $contact['phone'] ?? ''; - // 物流信息 - $logistics = $order['extensions']['logistics'] ?? []; - $order['delivery_type'] = ($order['delivery_type'] ?? '') ?: 'express'; - $order['delivery_name'] = $logistics['delivery_name'] ?? ''; - $order['delivery_id'] = $logistics['delivery_id'] ?? ''; - // 商品快照合成旧版 cartInfo,供订单商品组件展示 - $order['cartInfo'] = $this->services->buildLegacyCartInfo(is_array($order['extra_info'] ?? null) ? $order['extra_info'] : []); + + // 收货人:顶层 contact → extra_info.contact → delivery.contact + $extra = is_array($order['extra_info'] ?? null) ? $order['extra_info'] : []; + $contact = []; + if (is_array($order['contact'] ?? null) && $order['contact']) { + $contact = $order['contact']; + } elseif (is_array($extra['contact'] ?? null)) { + $contact = $extra['contact']; + } elseif (is_array($order['delivery']['contact'] ?? null)) { + $contact = $order['delivery']['contact']; + } + $order['real_name'] = trim((string)($contact['name'] ?? ($order['real_name'] ?? ''))); + if ($order['real_name'] === '') { + $order['real_name'] = trim((string)($order['nickname'] ?? '')); + } + $order['user_phone'] = trim((string)($contact['phone'] ?? ($order['user_phone'] ?? ''))); + // 收货地址 + if (empty($order['user_address'])) { + $addr = $contact['address'] ?? ($order['delivery']['user_address'] ?? ''); + if (is_array($addr)) { + $order['user_address'] = implode('', array_filter([ + $addr['province'] ?? '', + $addr['city'] ?? '', + $addr['district'] ?? '', + $addr['detail'] ?? '', + ])); + } else { + $order['user_address'] = trim((string)$addr); + } + } + + // 物流:顶层 → extensions → extra_info.delivery + $logistics = is_array($order['extensions']['logistics'] ?? null) ? $order['extensions']['logistics'] : []; + $deliveryExtra = is_array($extra['delivery'] ?? null) ? $extra['delivery'] : []; + if (empty($order['delivery_name'])) { + $order['delivery_name'] = (string)($logistics['delivery_name'] ?? ($deliveryExtra['delivery_name'] ?? '')); + } + if (empty($order['delivery_id'])) { + $order['delivery_id'] = (string)($logistics['delivery_id'] ?? ($deliveryExtra['delivery_id'] ?? '')); + } + if (empty($order['delivery_type'])) { + $shippingType = (int)($order['shipping_type'] ?? 0); + $order['delivery_type'] = (string)($logistics['delivery_type'] + ?? ($deliveryExtra['delivery_type'] ?? ($extra['delivery_type'] ?? ''))); + if ($order['delivery_type'] === '') { + $order['delivery_type'] = $shippingType === 2 ? 'pickup' : ($shippingType === 3 ? 'door' : 'express'); + } + } + + // 商品快照:extra_info.items 优先,缺省回退 order_items + if (empty($extra['items']) && !empty($order['order_items']) && is_array($order['order_items'])) { + $extra['items'] = $order['order_items']; + } + $order['cartInfo'] = $this->services->buildLegacyCartInfo($extra); + $order['mark'] = (string)($order['mark'] ?? ($extra['mark'] ?? '')); + $order['use_integral'] = (int)($order['use_integral'] ?? ($order['use_integral_num'] ?? 0)); + $order['system_store'] = is_array($order['store'] ?? null) + ? $order['store'] + : (is_array($order['system_store'] ?? null) ? $order['system_store'] : []); $order['mapKey'] = sys_config('tengxun_map_key'); /** @var PayChannelServices $payChannelServices */ $payChannelServices = app()->make(PayChannelServices::class); diff --git a/backend/app/services/order/OrderInvoiceServices.php b/backend/app/services/order/OrderInvoiceServices.php index ae30503bf..3083b2839 100644 --- a/backend/app/services/order/OrderInvoiceServices.php +++ b/backend/app/services/order/OrderInvoiceServices.php @@ -22,6 +22,7 @@ use crmeb\services\invoice\Invoice; use app\dao\order\OrderInvoiceDao; use app\services\user\UserInvoiceServices; use app\services\user\UserServices; +use crmeb\trade\order\type\OrderTypeRegistry; use think\facade\Log; @@ -78,10 +79,12 @@ class OrderInvoiceServices extends BaseService $field = 'id as invoice_id,order_id,header_type,type,name,duty_number,drawer_phone,email,tell,address,bank,card_number,is_invoice,invoice_number,remark as invoice_reamrk,invoice_time,add_time as invoice_add_time,unique_num,invoice_num,invoice_type,invoice_serial_number,red_invoice_num'; $where['is_pay'] = 1; $where['is_del'] = 0; - // 订单中台关联查询:仅选择中台表实际存在的字段 + // 订单中台关联查询:带 source_type/source_id,便于实时推导待发货/待收货 $list = $this->dao->getList($where, $field, ['order' => function ($query) { - $query->field('id,order_no,uid,pay_price,status_code,refund_status,extra_info,add_time'); + $query->field('id,order_no,uid,pay_price,status_code,refund_status,extra_info,add_time,source_type,source_id'); }], 'add_time desc', $page, $list); + // 按源订单类型批量解析业务子状态(extra_info 快照会被 syncStatus 覆盖成 processing,不能直接用) + $businessStatusMap = $this->resolveBusinessStatusMap($list); // 批量取下单用户,作为收货人姓名电话的兜底数据 $uids = array_filter(array_unique(array_column(array_column($list, 'order'), 'uid'))); $userList = $uids ? app()->make(UserServices::class)->getColumn([['uid', 'in', $uids]], 'uid,real_name,nickname,phone', 'uid') : []; @@ -100,29 +103,98 @@ class OrderInvoiceServices extends BaseService $contactPhone = trim((string)($contact['phone'] ?? '')); $item['real_name'] = $contactName !== '' ? $contactName : trim((string)($user['real_name'] ?? ($user['nickname'] ?? ''))); $item['user_phone'] = $contactPhone !== '' ? $contactPhone : trim((string)($user['phone'] ?? '')); - $item['status'] = $this->statusToLegacy($order['status_code'] ?? ''); + $statusCode = (string)($order['status_code'] ?? ''); + $item['status_code'] = $statusCode; + $centerId = (int)($order['id'] ?? 0); + $businessStatus = $businessStatusMap[$centerId] ?? null; + if (is_array($businessStatus)) { + if (empty($businessStatus['label']) && !empty($businessStatus['text'])) { + $businessStatus['label'] = $businessStatus['text']; + } + $item['business_status'] = $businessStatus; + // 列表唯一展示文案:优先业务子状态(待收货),否则中台统一状态 + $item['status_text'] = (string)($businessStatus['label'] ?: ($businessStatus['text'] ?? '')); + } else { + $item['business_status'] = null; + $item['status_text'] = ''; + } + if ($item['status_text'] === '') { + // 管理端与订单中台列表一致:processing 展示「待处理」 + $item['status_text'] = $statusCode === OrderCenter::STATUS_PROCESSING + ? '待处理' + : (OrderCenter::$statusMap[$statusCode] ?? ($statusCode !== '' ? $statusCode : '--')); + } + // 兼容旧前端/移动端数字状态 + $item['status'] = $this->statusToLegacy($statusCode); $item['refund_status'] = $order['refund_status'] ?? 0; $item['add_time'] = date('Y-m-d H:i:s', $order['add_time'] ?? $item['invoice_add_time'] ?? time()); $item['invoice_add_time'] = date('Y-m-d H:i:s', $item['invoice_add_time']); // 中台关联原始数据不再下发给前端 unset($item['order']); } + unset($item); $count = $this->dao->count($where); return compact('list', 'count'); } /** - * 订单中台状态码映射为旧版订单状态数值(兼容发票模块前端展示) + * 批量从源订单适配器推导业务子状态 + * @param array $list 含 order 关联的发票列表 + * @return array order_center.id => business_status + */ + protected function resolveBusinessStatusMap(array $list): array + { + $grouped = []; + $centerIndex = []; + foreach ($list as $row) { + $order = $row['order'] ?? []; + $centerId = (int)($order['id'] ?? 0); + $sourceType = (string)($order['source_type'] ?? ''); + $sourceId = (int)($order['source_id'] ?? 0); + if ($centerId <= 0 || $sourceType === '' || $sourceId <= 0) { + continue; + } + $grouped[$sourceType][$sourceId] = true; + $centerIndex[$sourceType][$sourceId][] = $centerId; + } + $result = []; + foreach ($grouped as $sourceType => $idMap) { + try { + $adapter = OrderTypeRegistry::getAdapter($sourceType); + $modelClass = $adapter::getModelClass(); + /** @var \crmeb\basic\BaseModel $model */ + $model = app()->make($modelClass); + $sourceRows = $model->whereIn('id', array_keys($idMap))->select()->toArray(); + foreach ($sourceRows as $sourceOrder) { + $sourceId = (int)($sourceOrder['id'] ?? 0); + $businessStatus = $adapter->resolveBusinessStatus($sourceOrder); + foreach ($centerIndex[$sourceType][$sourceId] ?? [] as $centerId) { + $result[$centerId] = $businessStatus; + } + } + } catch (\Throwable $e) { + Log::warning('发票列表推导订单业务状态失败: ' . $e->getMessage(), ['source_type' => $sourceType]); + } + } + return $result; + } + + /** + * 订单中台状态码映射为旧版订单状态数值(兼容移动端发票列表 _type) * @param string $statusCode * @return int */ public function statusToLegacy(string $statusCode): int { return match ($statusCode) { + OrderCenter::STATUS_PENDING_PAYMENT => 0, OrderCenter::STATUS_PROCESSING => 0, OrderCenter::STATUS_PENDING_REVIEW => 2, OrderCenter::STATUS_COMPLETED => 3, + OrderCenter::STATUS_CANCELED => -1, + OrderCenter::STATUS_AFTER_SALE, OrderCenter::STATUS_REFUNDING => -3, OrderCenter::STATUS_REFUNDED => -2, + OrderCenter::STATUS_DELETED => -4, default => 0, }; } @@ -145,11 +217,13 @@ class OrderInvoiceServices extends BaseService $extra = $order['extra_info'] ?? ''; $extra = is_string($extra) ? (json_decode($extra, true) ?: []) : ($extra ?: []); $order['cartInfo'] = $this->buildLegacyCartInfo($extra); + $order['pay_price'] = $order['pay_price'] ?? '0.00'; // 移动端跳转开票详情携带的订单号对应中台 order_no $order['order_id'] = $order['order_no'] ?? ''; unset($order['extra_info']); $item['order'] = $order; } + unset($item); return $list; } diff --git a/backend/public/install/data/page_link_data.sql b/backend/public/install/data/page_link_data.sql index 81d02a7f7..fa990edac 100755 --- a/backend/public/install/data/page_link_data.sql +++ b/backend/public/install/data/page_link_data.sql @@ -26,7 +26,7 @@ INSERT INTO `eb_page_link` (`id`, `cate_id`, `type`, `name`, `url`, `param`, `ex (37, 20, 1, '待评价订单', '/pages/goods/order_list/index?status=3', '', '', 1, 0, 1772520919), (38, 20, 1, '联系客服', '/pages/extension/customer_list/chat', '', '', 1, 0, 1772520919), (39, 20, 1, '我的收藏', '/pages/users/user_goods_collection/index', '', '', 1, 0, 1772520919), -(40, 20, 1, '发票管理', '/pages/users/user_invoice_list/index', '', '', 1, 0, 1772520919), +(40, 20, 1, '发票管理', '/pages/users/user_invoice_list/index', '', '', 1, 2, 1772520919), (41, 20, 1, '每日签到', '/pages/users/user_sgin/index', '', '', 1, 0, 1772520919), (42, 20, 1, '客服接待', '/kefu/mobile_list', '', '', 1, 0, 1772520919), -(54, 20, 1, '订单核销', '/pages/admin/order_cancellation/index', '', '', 1, 0, 1772520919); \ No newline at end of file +(54, 20, 1, '订单核销', '/pages/admin/order_cancellation/index', '', '', 1, 1, 1772520919); \ No newline at end of file diff --git a/frontend/admin/src/pages/order/invoice/index.vue b/frontend/admin/src/pages/order/invoice/index.vue index e93357e12..1a4a329a3 100644 --- a/frontend/admin/src/pages/order/invoice/index.vue +++ b/frontend/admin/src/pages/order/invoice/index.vue @@ -83,11 +83,7 @@ @@ -131,8 +127,8 @@ > - 操作 - + 操作 + 订单信息 @@ -332,6 +328,77 @@ const orderData = ref({ const orderId = ref(0); const invoiceId = ref(0); +/** 中台统一状态码(有业务子状态时不叠展示「待处理」等) */ +const CENTER_STATUS_CODES = [ + 'pending_payment', + 'processing', + 'pending_review', + 'completed', + 'canceled', + 'after_sale', + 'refunding', + 'refunded', + 'deleted', +]; + +/** 与订单中台列表 statusCodeOptions 同口径 */ +const ORDER_STATUS_OPTIONS = [ + { key: 'pending_payment', label: '待支付' }, + { key: 'processing', label: '待处理' }, + { key: 'pending_review', label: '待评价' }, + { key: 'completed', label: '已完成' }, + { key: 'canceled', label: '已取消' }, + { key: 'after_sale', label: '售后中' }, + { key: 'refunding', label: '退款中' }, + { key: 'refunded', label: '已退款' }, + { key: 'deleted', label: '已删除' }, +]; + +function getBusinessStatusText(row) { + const bs = row?.business_status; + if (!bs || typeof bs !== 'object') return ''; + const text = String(bs.label || bs.text || '').trim(); + if (!text) return ''; + const code = String(bs.code || ''); + const genericTexts = ORDER_STATUS_OPTIONS.map((o) => o.label).concat(['进行中']); + // 待发货/待收货等业务文案优先;中台统一码快照(待处理/进行中)忽略 + if (!genericTexts.includes(text)) return text; + if (code && !CENTER_STATUS_CODES.includes(code)) return text; + return ''; +} + +function getOrderStatusLabel(row) { + if (row && Number(row.is_del) === 1) return '已删除'; + // 后端已按源订单实时推导 status_text(待收货/待发货优先) + if (row?.status_text) return row.status_text; + const businessText = getBusinessStatusText(row); + if (businessText) return businessText; + const code = row?.status_code; + const item = ORDER_STATUS_OPTIONS.find((opt) => opt.key === code); + return item ? item.label : code || '--'; +} + +function getOrderStatusClass(row) { + if (row && Number(row.is_del) === 1) return 'danger'; + if (getBusinessStatusText(row)) return 'primary'; + const map = { + pending_payment: 'warning', + processing: 'primary', + pending_review: 'success', + completed: 'success', + canceled: 'danger', + after_sale: 'warning', + refunding: 'warning', + refunded: 'info', + deleted: 'danger', + }; + return map[row?.status_code] || 'info'; +} + +function isRefundedOrder(row) { + return row?.status_code === 'refunded' || Number(row?.status) === -2; +} + // created getTabs(); getList(); @@ -541,4 +608,8 @@ function onClickTab() { :deep(.order-detail-drawer .el-drawer__body) { padding: 20px 0 !important; } +.business-status { + font-size: 12px; + color: #999; +} diff --git a/frontend/uni-app/src/api/order.js b/frontend/uni-app/src/api/order.js index 902d17e43..3a12f9236 100644 --- a/frontend/uni-app/src/api/order.js +++ b/frontend/uni-app/src/api/order.js @@ -138,11 +138,13 @@ export function getGiftOrderDetail(id) { return request.get('order/gift_detail/' + id); } /** - * 订单详情 - * @param string uni + * 订单详情(兼容旧调用:已迁移至中台 center/order/detail) + * @param string uni 订单号 */ export function getOrderDetail(uni, cart_id) { - return request.get('order/detail/' + uni + `${cart_id ? `/${cart_id}`:''}`); + // 旧路由 order/detail 已下线;统一走中台详情。cart_id 参数已废弃。 + void cart_id; + return request.get(`center/order/detail/${uni}`); } /** * 退款订单详情 diff --git a/frontend/uni-app/src/dynamic-pages/api/action-map.js b/frontend/uni-app/src/dynamic-pages/api/action-map.js index d194c40c4..cd4401d06 100644 --- a/frontend/uni-app/src/dynamic-pages/api/action-map.js +++ b/frontend/uni-app/src/dynamic-pages/api/action-map.js @@ -128,14 +128,18 @@ export default { buyAgain(order, params) { repurchaseToOrderCreate(order, params); }, - /** 删除订单 */ - deleteOrder(order, params) { + /** 删除订单(详情页通过 context.onDelete 自行调接口并返回列表;列表页走事件总线) */ + deleteOrder(order, params, context) { const orderNo = params.order_no || order.order_no || ''; uni.showModal({ title: i18n.t(`提示`), content: i18n.t(`确定删除该订单吗?删除后不可恢复`), success: (res) => { if (res.confirm) { + if (context && typeof context.onDelete === 'function') { + context.onDelete({ order_no: orderNo }); + return; + } uni.$emit('order:delete', { order_no: orderNo }); } }, @@ -208,4 +212,24 @@ export default { refunded(order, params) { uni.navigateTo({ url: routes.orderDetail + '?order_no=' + order.order_no }); }, + /** + * 申请开票(详情页通过 context.onApplyInvoice 打开抬头选择弹窗) + */ + applyInvoice(order, params, context) { + if (context && typeof context.onApplyInvoice === 'function') { + context.onApplyInvoice(params || {}); + return; + } + uni.showToast({ title: i18n.t(`请在订单详情中申请开票`), icon: 'none' }); + }, + /** + * 查看发票(详情页通过 context.onViewInvoice 打开发票信息弹窗) + */ + viewInvoice(order, params, context) { + if (context && typeof context.onViewInvoice === 'function') { + context.onViewInvoice(params || {}); + return; + } + uni.showToast({ title: i18n.t(`请在订单详情中查看发票`), icon: 'none' }); + }, }; diff --git a/frontend/uni-app/src/dynamic-pages/components/order/create/OrderInvoicePanel.vue b/frontend/uni-app/src/dynamic-pages/components/order/create/OrderInvoicePanel.vue index 065cbacdf..ea72bcbf9 100644 --- a/frontend/uni-app/src/dynamic-pages/components/order/create/OrderInvoicePanel.vue +++ b/frontend/uni-app/src/dynamic-pages/components/order/create/OrderInvoicePanel.vue @@ -107,8 +107,8 @@ const props = defineProps({ }, /** 当前选中的抬头 ID(字符串) */ checked: { type: String, default: '' }, - /** 是否启用专用发票(受 features.special_invoice 控制) */ - specialInvoice: { type: Boolean, default: true }, + /** 是否启用专用发票(受 features.special_invoice 控制,缺省关闭) */ + specialInvoice: { type: Boolean, default: false }, /** 跳转 user_invoice_form 时携带的回跳参数(不含 ?) */ urlQuery: { type: String, default: '' }, /** 弹窗显隐(支持 v-model:popupShow) */ diff --git a/frontend/uni-app/src/dynamic-pages/components/order/detail/ButtonGroup.vue b/frontend/uni-app/src/dynamic-pages/components/order/detail/ButtonGroup.vue index f89768482..bdd655cfc 100644 --- a/frontend/uni-app/src/dynamic-pages/components/order/detail/ButtonGroup.vue +++ b/frontend/uni-app/src/dynamic-pages/components/order/detail/ButtonGroup.vue @@ -1,20 +1,43 @@ @@ -32,7 +55,7 @@ export default { diff --git a/frontend/uni-app/src/pages/goods/components/invoicePicker/index.vue b/frontend/uni-app/src/pages/goods/components/invoicePicker/index.vue index 51edf06e7..22d6c307e 100644 --- a/frontend/uni-app/src/pages/goods/components/invoicePicker/index.vue +++ b/frontend/uni-app/src/pages/goods/components/invoicePicker/index.vue @@ -1,9 +1,12 @@