2452 lines
89 KiB
Vue
2452 lines
89 KiB
Vue
<template>
|
||
<div class="app-container">
|
||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="90px">
|
||
<el-form-item label="订单编号" prop="orderNo">
|
||
<el-input
|
||
v-model="queryParams.orderNo"
|
||
placeholder="请输入订单编号"
|
||
clearable
|
||
@keyup.enter.native="handleQuery"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="品牌方" prop="brandTenantId">
|
||
<el-select v-model="queryParams.brandTenantId" placeholder="请选择品牌方" clearable filterable>
|
||
<el-option
|
||
v-for="item in brandTenantList"
|
||
:key="item.id"
|
||
:label="item.name"
|
||
:value="item.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="镜片厂" prop="lensFactoryTenantId">
|
||
<el-select v-model="queryParams.lensFactoryTenantId" placeholder="请选择镜片厂" clearable filterable>
|
||
<el-option
|
||
v-for="item in lensFactoryList"
|
||
:key="item.id"
|
||
:label="item.name"
|
||
:value="item.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="订单状态" prop="orderStatus">
|
||
<el-select v-model="queryParams.orderStatus" placeholder="请选择订单状态" clearable @change="handleOrderStatusChange">
|
||
<el-option
|
||
v-for="dict in dict.type.jy_order_status"
|
||
:key="dict.value"
|
||
:label="dict.label"
|
||
:value="dict.value"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="采购结算" prop="purchaseSettleStatus">
|
||
<el-select v-model="queryParams.purchaseSettleStatus" placeholder="请选择" clearable>
|
||
<el-option
|
||
v-for="dict in dict.type.jy_purchase_settle_status"
|
||
:key="dict.value"
|
||
:label="dict.label"
|
||
:value="dict.value"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="销售结算" prop="saleSettleStatus">
|
||
<el-select v-model="queryParams.saleSettleStatus" placeholder="请选择" clearable>
|
||
<el-option
|
||
v-for="dict in dict.type.jy_sale_settle_status"
|
||
:key="dict.value"
|
||
:label="dict.label"
|
||
:value="dict.value"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="收货人" prop="receiverName">
|
||
<el-input
|
||
v-model="queryParams.receiverName"
|
||
placeholder="请输入收货人姓名"
|
||
clearable
|
||
@keyup.enter.native="handleQuery"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
|
||
<el-row :gutter="10" class="mb8">
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
type="primary"
|
||
plain
|
||
icon="el-icon-plus"
|
||
size="mini"
|
||
@click="handleAdd"
|
||
v-hasPermi="['jysystem:order:add']"
|
||
>新增</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
type="success"
|
||
plain
|
||
icon="el-icon-edit"
|
||
size="mini"
|
||
:disabled="single"
|
||
@click="handleUpdate"
|
||
v-hasPermi="['jysystem:order:edit']"
|
||
>修改</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
type="danger"
|
||
plain
|
||
icon="el-icon-delete"
|
||
size="mini"
|
||
:disabled="multiple"
|
||
@click="handleDelete"
|
||
v-hasPermi="['jysystem:order:remove']"
|
||
>删除</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
type="info"
|
||
plain
|
||
icon="el-icon-document"
|
||
size="mini"
|
||
@click="handleGenerateSettlement"
|
||
v-hasPermi="['jysystem:feeSettlement:generate']"
|
||
>生成费用结算单</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
type="warning"
|
||
plain
|
||
icon="el-icon-download"
|
||
size="mini"
|
||
:disabled="multiple"
|
||
@click="handleBatchExportExcel"
|
||
v-hasPermi="['jysystem:order:export']"
|
||
>批量导出Excel</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
type="info"
|
||
plain
|
||
icon="el-icon-download"
|
||
size="mini"
|
||
:disabled="multiple"
|
||
@click="handleBatchExportPdf"
|
||
v-hasPermi="['jysystem:order:export']"
|
||
>批量导出PDF</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
type="warning"
|
||
plain
|
||
icon="el-icon-download"
|
||
size="mini"
|
||
@click="handleExport"
|
||
v-hasPermi="['jysystem:order:export']"
|
||
>导出</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
:type="activeQuickFilter === 'pendingAssign' ? 'primary' : ''"
|
||
plain
|
||
size="mini"
|
||
@click="handleQuickFilter('pendingAssign')"
|
||
>待分配</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
:type="activeQuickFilter === 'exchangeApply' ? 'primary' : ''"
|
||
plain
|
||
size="mini"
|
||
@click="handleQuickFilter('exchangeApply')"
|
||
>换货申请</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button
|
||
:type="activeQuickFilter === 'exchangeRejected' ? 'primary' : ''"
|
||
plain
|
||
size="mini"
|
||
@click="handleQuickFilter('exchangeRejected')"
|
||
>拒绝换货申请</el-button>
|
||
</el-col>
|
||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||
</el-row>
|
||
|
||
<el-table v-loading="loading" :data="orderList" @selection-change="handleSelectionChange">
|
||
<el-table-column type="selection" width="55" align="center" />
|
||
<el-table-column label="订单编号" align="center" prop="orderNo" min-width="200" show-overflow-tooltip />
|
||
<el-table-column label="品牌方" align="center" prop="brandTenantName" min-width="110" show-overflow-tooltip />
|
||
<el-table-column label="镜片厂" align="center" min-width="110" show-overflow-tooltip>
|
||
<template slot-scope="scope">
|
||
<span>{{ formatLensFactory(scope.row) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="通用镜片" align="center" min-width="140" show-overflow-tooltip>
|
||
<template slot-scope="scope">
|
||
<span>{{ formatLens(scope.row) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="B价格" align="center" width="90">
|
||
<template slot-scope="scope">
|
||
<span>{{ formatPriceAmount(formatPriceB(scope.row)) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="C价格" align="center" width="90">
|
||
<template slot-scope="scope">
|
||
<span>{{ formatPriceAmount(formatPriceC(scope.row)) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="物流费用" align="center" width="90">
|
||
<template slot-scope="scope">
|
||
<span>{{ formatPriceAmount(formatLogisticsFee(scope.row)) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="渐进多焦点价格" align="center" width="120">
|
||
<template slot-scope="scope">
|
||
<span>{{ formatPriceAmount(formatProgressiveMultifocalPrice(scope.row)) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="订单状态" align="center" prop="orderStatus" width="130">
|
||
<template slot-scope="scope">
|
||
<el-select
|
||
v-if="canEditOrderStatus"
|
||
v-model="scope.row.orderStatus"
|
||
size="mini"
|
||
class="order-status-select"
|
||
@visible-change="visible => handleStatusSelectVisible(scope.row, visible)"
|
||
@change="handleOrderStatusChange(scope.row)"
|
||
>
|
||
<el-option
|
||
v-for="dict in dict.type.jy_order_status"
|
||
:key="dict.value"
|
||
:label="dict.label"
|
||
:value="dict.value"
|
||
/>
|
||
</el-select>
|
||
<dict-tag v-else :options="dict.type.jy_order_status" :value="scope.row.orderStatus"/>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="采购结算" align="center" prop="purchaseSettleStatus" width="90">
|
||
<template slot-scope="scope">
|
||
<dict-tag :options="dict.type.jy_purchase_settle_status" :value="scope.row.purchaseSettleStatus"/>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="销售结算" align="center" prop="saleSettleStatus" width="90">
|
||
<template slot-scope="scope">
|
||
<dict-tag :options="dict.type.jy_sale_settle_status" :value="scope.row.saleSettleStatus"/>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="收货人" align="center" prop="receiverName" width="90" />
|
||
<el-table-column label="手机号" align="center" prop="receiverPhone" width="120" />
|
||
<el-table-column label="收货地址" align="center" prop="receiverAddress" min-width="160" show-overflow-tooltip />
|
||
<el-table-column label="创建时间" align="center" prop="createTime" width="160" />
|
||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="420" fixed="right">
|
||
<template slot-scope="scope">
|
||
<el-button
|
||
size="mini"
|
||
type="text"
|
||
icon="el-icon-view"
|
||
@click="handleDetail(scope.row)"
|
||
v-hasPermi="['jysystem:order:query']"
|
||
>详情</el-button>
|
||
<el-button
|
||
v-if="canViewLogistics(scope.row)"
|
||
size="mini"
|
||
type="text"
|
||
@click="handleViewLogistics(scope.row)"
|
||
v-hasPermi="['jysystem:order:query']"
|
||
>查看物流</el-button>
|
||
<el-button
|
||
v-if="scope.row.orderStatus === ORDER_STATUS_SUBMITTED || scope.row.orderStatus === ORDER_STATUS_REJECTED || scope.row.orderStatus === ORDER_STATUS_CANCELLED || scope.row.orderStatus === ORDER_STATUS_WITHDRAWN"
|
||
size="mini"
|
||
type="text"
|
||
icon="el-icon-s-check"
|
||
@click="handleAssign(scope.row)"
|
||
v-hasPermi="['jysystem:order:edit']"
|
||
>分配</el-button>
|
||
<el-button
|
||
v-if="scope.row.orderStatus === ORDER_STATUS_SUBMITTED"
|
||
size="mini"
|
||
type="text"
|
||
icon="el-icon-close"
|
||
@click="handleReject(scope.row)"
|
||
v-hasPermi="['jysystem:order:edit']"
|
||
>驳回</el-button>
|
||
<el-button
|
||
v-if="scope.row.orderStatus === ORDER_STATUS_WITHDRAWN"
|
||
size="mini"
|
||
type="text"
|
||
icon="el-icon-circle-close"
|
||
@click="handleClose(scope.row)"
|
||
v-hasPermi="['jysystem:order:edit']"
|
||
>关闭</el-button>
|
||
<el-button
|
||
v-if="canCompleteOrder(scope.row)"
|
||
size="mini"
|
||
type="text"
|
||
icon="el-icon-check"
|
||
@click="handleComplete(scope.row)"
|
||
v-hasPermi="['jysystem:order:edit']"
|
||
>完成</el-button>
|
||
<el-button
|
||
v-if="scope.row.orderStatus === ORDER_STATUS_EXCHANGE_APPLY"
|
||
size="mini"
|
||
type="text"
|
||
icon="el-icon-check"
|
||
style="color: #67c23a"
|
||
@click="handleAgreeExchange(scope.row)"
|
||
v-hasPermi="['jysystem:order:edit']"
|
||
>同意换货申请</el-button>
|
||
<el-button
|
||
v-if="scope.row.orderStatus === ORDER_STATUS_EXCHANGE_APPLY"
|
||
size="mini"
|
||
type="text"
|
||
icon="el-icon-close"
|
||
style="color: #f56c6c"
|
||
@click="handleRejectExchange(scope.row)"
|
||
v-hasPermi="['jysystem:order:edit']"
|
||
>拒绝换货申请</el-button>
|
||
<el-button
|
||
size="mini"
|
||
type="text"
|
||
icon="el-icon-edit"
|
||
@click="handleUpdate(scope.row)"
|
||
v-hasPermi="['jysystem:order:edit']"
|
||
>修改</el-button>
|
||
<el-button
|
||
size="mini"
|
||
type="text"
|
||
icon="el-icon-delete"
|
||
@click="handleDelete(scope.row)"
|
||
v-hasPermi="['jysystem:order:remove']"
|
||
>删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<pagination
|
||
v-show="total>0"
|
||
:total="total"
|
||
:page.sync="queryParams.pageNum"
|
||
:limit.sync="queryParams.pageSize"
|
||
@pagination="getList"
|
||
/>
|
||
|
||
<el-dialog
|
||
:visible.sync="open"
|
||
width="1200px"
|
||
append-to-body
|
||
destroy-on-close
|
||
custom-class="lens-order-form-dialog"
|
||
>
|
||
<div slot="title" class="lens-dialog-header">
|
||
<div class="lens-dialog-title-wrap">
|
||
<h3 class="lens-dialog-title">{{ title }}</h3>
|
||
<p class="lens-dialog-subtitle">{{ formDialogSubtitle }}</p>
|
||
</div>
|
||
</div>
|
||
<el-form ref="form" :model="form" :rules="rules" label-width="110px" class="lens-order-form">
|
||
<section class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">01</span>
|
||
<div class="section-text">
|
||
<h4>订单信息</h4>
|
||
<p>订单基础信息、品牌方与镜片配置</p>
|
||
</div>
|
||
</div>
|
||
<el-row :gutter="20" class="section-body">
|
||
<el-col :span="12">
|
||
<el-form-item label="订单编号" prop="orderNo">
|
||
<el-input v-model="form.orderNo" placeholder="留空则自动生成" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="订单状态" prop="orderStatus">
|
||
<el-select v-model="form.orderStatus" placeholder="请选择订单状态" style="width: 100%">
|
||
<el-option
|
||
v-for="dict in dict.type.jy_order_status"
|
||
:key="dict.value"
|
||
:label="dict.label"
|
||
:value="dict.value"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="品牌方" prop="brandTenantId">
|
||
<el-select v-model="form.brandTenantId" placeholder="请选择品牌方" clearable filterable style="width: 100%">
|
||
<el-option
|
||
v-for="item in brandTenantList"
|
||
:key="item.id"
|
||
:label="item.name"
|
||
:value="item.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="镜片厂" prop="lensFactoryTenantId">
|
||
<el-select v-model="form.lensFactoryTenantId" placeholder="请选择镜片厂" clearable filterable style="width: 100%" @change="handleFormLensFactoryChange">
|
||
<el-option
|
||
v-for="item in lensFactoryList"
|
||
:key="item.id"
|
||
:label="item.name"
|
||
:value="item.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="产品">
|
||
<el-input :value="formatProduct(form)" disabled />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="通用镜片" prop="lensId">
|
||
<el-select v-model="form.lensId" placeholder="请选择通用镜片" clearable filterable style="width: 100%">
|
||
<el-option
|
||
v-for="item in lensList"
|
||
:key="item.id"
|
||
:label="formatLensOption(item)"
|
||
:value="item.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
</section>
|
||
|
||
<section class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">02</span>
|
||
<div class="section-text">
|
||
<h4>价格与结算</h4>
|
||
<p>价格信息及采购、销售结算状态</p>
|
||
</div>
|
||
</div>
|
||
<el-row :gutter="20" class="section-body">
|
||
<el-col :span="8">
|
||
<el-form-item label="B价格" prop="priceB">
|
||
<el-input-number v-model="form.priceB" :precision="2" :min="0" controls-position="right" style="width: 100%" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="C价格" prop="priceC">
|
||
<el-input-number v-model="form.priceC" :precision="2" :min="0" controls-position="right" style="width: 100%" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="物流费用" prop="logisticsFee">
|
||
<el-input-number v-model="form.logisticsFee" :precision="2" :min="0" controls-position="right" style="width: 100%" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="渐进多焦点">
|
||
<el-switch
|
||
v-model="form.progressiveMultifocal"
|
||
:active-value="1"
|
||
:inactive-value="0"
|
||
active-text="是"
|
||
inactive-text="否"
|
||
@change="handleProgressiveMultifocalChange"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col v-if="form.progressiveMultifocal === 1" :span="8">
|
||
<el-form-item label="渐进多焦点价格" prop="progressiveMultifocalPrice">
|
||
<el-input-number
|
||
v-model="form.progressiveMultifocalPrice"
|
||
:precision="2"
|
||
:min="0"
|
||
controls-position="right"
|
||
style="width: 100%"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="采购结算" prop="purchaseSettleStatus">
|
||
<el-radio-group v-model="form.purchaseSettleStatus">
|
||
<el-radio
|
||
v-for="dict in dict.type.jy_purchase_settle_status"
|
||
:key="dict.value"
|
||
:label="dict.value"
|
||
>{{ dict.label }}</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="销售结算" prop="saleSettleStatus">
|
||
<el-radio-group v-model="form.saleSettleStatus">
|
||
<el-radio
|
||
v-for="dict in dict.type.jy_sale_settle_status"
|
||
:key="dict.value"
|
||
:label="dict.value"
|
||
>{{ dict.label }}</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
</section>
|
||
|
||
<section class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">03</span>
|
||
<div class="section-text">
|
||
<h4>收货信息</h4>
|
||
<p>镜片寄送地址与联系方式</p>
|
||
</div>
|
||
</div>
|
||
<el-row :gutter="20" class="section-body">
|
||
<el-col :span="8">
|
||
<el-form-item label="收货人姓名" prop="receiverName">
|
||
<el-input v-model="form.receiverName" placeholder="请输入收货人姓名" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="收货人手机号" prop="receiverPhone">
|
||
<el-input v-model="form.receiverPhone" placeholder="请输入收货人手机号" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="24">
|
||
<el-form-item label="收货人地址" prop="receiverAddress">
|
||
<el-input v-model="form.receiverAddress" placeholder="请输入收货人地址" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
</section>
|
||
|
||
<section class="lens-form-section lens-form-section--optometry">
|
||
<div class="section-head">
|
||
<span class="section-index">04</span>
|
||
<div class="section-text">
|
||
<h4>验光参数</h4>
|
||
<p>录入左右眼验光数据</p>
|
||
</div>
|
||
</div>
|
||
<div class="section-body">
|
||
<el-table :data="form.optometryList" class="lens-optometry-table" size="small">
|
||
<el-table-column label="左右" align="center" width="100">
|
||
<template slot-scope="scope">
|
||
<span>{{ scope.row.eyeSide === 'OS' ? '左眼(OS)' : '右眼(OD)' }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="球镜S(度)" align="center" min-width="90">
|
||
<template slot-scope="scope">
|
||
<el-input-number v-model="scope.row.sphereS" :precision="2" :step="0.25" controls-position="right" style="width: 100%" @change="val => onSphereSChange(val, scope.row)" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="柱镜C(度)" align="center" min-width="90">
|
||
<template slot-scope="scope">
|
||
<el-input-number
|
||
v-model="scope.row.cylinderC"
|
||
:precision="2"
|
||
:step="0.25"
|
||
:min="getCylinderCMin(scope.row)"
|
||
:max="getCylinderCMax(scope.row)"
|
||
controls-position="right"
|
||
style="width: 100%"
|
||
@change="val => onCylinderCChange(val, scope.row)"
|
||
/>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="轴位A(度)" align="center" min-width="80">
|
||
<template slot-scope="scope">
|
||
<el-input-number v-model="scope.row.axisA" :min="0" :max="180" :disabled="!isAxisAEditable(scope.row)" controls-position="right" style="width: 100%" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="瞳距(mm)" align="center" min-width="90">
|
||
<template slot-scope="scope">
|
||
<el-input-number v-model="scope.row.pd" :precision="2" :min="0" controls-position="right" style="width: 100%" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column v-if="form.progressiveMultifocal === 1" label="瞳高(mm)" align="center" min-width="80">
|
||
<template slot-scope="scope">
|
||
<el-input-number v-model="scope.row.pupilHeight" :precision="2" :min="0" controls-position="right" style="width: 100%" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="远用VA(视力值)" align="center" min-width="90">
|
||
<template slot-scope="scope">
|
||
<el-input v-model="scope.row.distanceVa" placeholder="远用VA" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column v-if="form.progressiveMultifocal === 1" label="近用ADD(屈光度)" align="center" min-width="100">
|
||
<template slot-scope="scope">
|
||
<el-input-number v-model="scope.row.nearAdd" :precision="2" :step="0.25" :min="0.75" :max="4" controls-position="right" style="width: 100%" />
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">05</span>
|
||
<div class="section-text">
|
||
<h4>附件与备注</h4>
|
||
<p>上传相关资料并补充说明</p>
|
||
</div>
|
||
</div>
|
||
<el-row :gutter="20" class="section-body">
|
||
<el-col :span="24">
|
||
<el-form-item label="附件" prop="attachment">
|
||
<file-upload v-model="form.attachment" :limit="5" :file-type="attachmentFileTypes" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="24">
|
||
<el-form-item label="备注" prop="remark">
|
||
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
</section>
|
||
</el-form>
|
||
<div slot="footer" class="lens-dialog-footer">
|
||
<el-button class="lens-btn-ghost" @click="cancel">取 消</el-button>
|
||
<el-button class="lens-btn-primary" @click="submitForm">确 定</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<el-dialog title="驳回订单" :visible.sync="rejectOpen" width="520px" append-to-body>
|
||
<el-form ref="rejectForm" :model="rejectForm" :rules="rejectRules" label-width="80px">
|
||
<el-form-item label="订单编号">
|
||
<span>{{ rejectForm.orderNo || '-' }}</span>
|
||
</el-form-item>
|
||
<el-form-item label="驳回原因" prop="reason">
|
||
<el-input
|
||
v-model="rejectForm.reason"
|
||
type="textarea"
|
||
:rows="5"
|
||
placeholder="请输入驳回原因"
|
||
maxlength="500"
|
||
show-word-limit
|
||
/>
|
||
</el-form-item>
|
||
</el-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button type="danger" :loading="rejectLoading" @click="submitReject">确 定</el-button>
|
||
<el-button @click="rejectOpen = false">取 消</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<el-dialog title="拒绝换货申请" :visible.sync="exchangeRejectOpen" width="520px" append-to-body>
|
||
<el-form ref="exchangeRejectForm" :model="exchangeRejectForm" :rules="exchangeRejectRules" label-width="110px">
|
||
<el-form-item label="订单编号">
|
||
<span>{{ exchangeRejectForm.orderNo || '-' }}</span>
|
||
</el-form-item>
|
||
<el-form-item label="拒绝原因" prop="reason">
|
||
<el-input
|
||
v-model="exchangeRejectForm.reason"
|
||
type="textarea"
|
||
:rows="5"
|
||
placeholder="请输入拒绝换货申请原因"
|
||
maxlength="500"
|
||
show-word-limit
|
||
/>
|
||
</el-form-item>
|
||
</el-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button type="danger" :loading="exchangeRejectLoading" @click="submitExchangeReject">确 定</el-button>
|
||
<el-button @click="exchangeRejectOpen = false">取 消</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<el-dialog
|
||
:key="assignDialogKey"
|
||
:visible.sync="assignOpen"
|
||
width="720px"
|
||
append-to-body
|
||
destroy-on-close
|
||
custom-class="lens-order-detail-dialog"
|
||
@closed="resetAssignDialog"
|
||
>
|
||
<div slot="title" class="lens-dialog-header">
|
||
<div class="lens-dialog-title-wrap">
|
||
<h3 class="lens-dialog-title">分配镜片厂</h3>
|
||
<p class="lens-dialog-subtitle">{{ assignDialogSubtitle }}</p>
|
||
</div>
|
||
</div>
|
||
<el-form ref="assignForm" :model="assignForm" :rules="assignRules" label-width="110px" class="lens-order-detail">
|
||
<section class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">01</span>
|
||
<div class="section-text">
|
||
<h4>订单信息</h4>
|
||
<p>待分配订单的基础信息</p>
|
||
</div>
|
||
</div>
|
||
<div class="section-body">
|
||
<el-descriptions :column="2" border size="small" class="detail-descriptions">
|
||
<el-descriptions-item label="订单编号">{{ assignForm.orderNo || '-' }}</el-descriptions-item>
|
||
<el-descriptions-item label="渐进多焦点">{{ assignForm.progressiveMultifocal === 1 ? '是' : '否' }}</el-descriptions-item>
|
||
<el-descriptions-item label="通用镜片" :span="2">{{ assignForm.lensText || '-' }}</el-descriptions-item>
|
||
</el-descriptions>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">02</span>
|
||
<div class="section-text">
|
||
<h4>分配镜片厂</h4>
|
||
<p>选择承接该订单的镜片厂</p>
|
||
</div>
|
||
</div>
|
||
<div class="section-body">
|
||
<el-form-item label="镜片厂" prop="lensFactoryTenantId">
|
||
<el-select
|
||
v-model="assignForm.lensFactoryTenantId"
|
||
placeholder="请选择镜片厂"
|
||
clearable
|
||
filterable
|
||
style="width: 100%"
|
||
@change="handleAssignFactoryChange"
|
||
>
|
||
<el-option
|
||
v-for="item in assignLensFactoryList"
|
||
:key="item.id"
|
||
:label="item.name"
|
||
:value="item.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</div>
|
||
</section>
|
||
|
||
<section v-if="hasAssignPreview" class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">03</span>
|
||
<div class="section-text">
|
||
<h4>分配价格</h4>
|
||
<p>根据镜片厂自动核算的价格信息</p>
|
||
</div>
|
||
</div>
|
||
<div class="section-body">
|
||
<el-descriptions :column="2" border size="small" class="detail-descriptions detail-descriptions--price">
|
||
<el-descriptions-item v-if="assignPreview.priceB != null" label="B价格">
|
||
{{ formatPriceAmount(assignPreview.priceB) }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item v-if="assignPreview.priceC != null" label="C价格">
|
||
{{ formatPriceAmount(assignPreview.priceC) }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item
|
||
v-if="assignForm.progressiveMultifocal === 1 && assignPreview.progressiveMultifocalPrice != null"
|
||
label="渐进多焦点价格"
|
||
:span="2"
|
||
>
|
||
{{ formatPriceAmount(assignPreview.progressiveMultifocalPrice) }}
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
</div>
|
||
</section>
|
||
</el-form>
|
||
<div slot="footer" class="lens-dialog-footer">
|
||
<el-button class="lens-btn-ghost" @click="assignOpen = false">取 消</el-button>
|
||
<el-button class="lens-btn-primary" :loading="assignLoading" @click="submitAssign">保 存</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<el-dialog
|
||
:visible.sync="detailOpen"
|
||
width="1200px"
|
||
append-to-body
|
||
custom-class="lens-order-detail-dialog"
|
||
>
|
||
<div slot="title" class="lens-dialog-header">
|
||
<div class="lens-dialog-title-wrap">
|
||
<h3 class="lens-dialog-title">订单详情</h3>
|
||
<p class="lens-dialog-subtitle">{{ detailDialogSubtitle }}</p>
|
||
</div>
|
||
</div>
|
||
<div class="lens-order-detail">
|
||
<section class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">01</span>
|
||
<div class="section-text">
|
||
<h4>订单信息</h4>
|
||
<p>订单基础信息、品牌方与镜片配置</p>
|
||
</div>
|
||
</div>
|
||
<div class="section-body">
|
||
<el-descriptions :column="2" border size="small" class="detail-descriptions">
|
||
<el-descriptions-item label="订单编号">{{ detail.orderNo }}</el-descriptions-item>
|
||
<el-descriptions-item label="订单状态">
|
||
<dict-tag :options="dict.type.jy_order_status" :value="detail.orderStatus" />
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="品牌方">{{ detail.brandTenantName || '-' }}</el-descriptions-item>
|
||
<el-descriptions-item label="产品">{{ formatProduct(detail) }}</el-descriptions-item>
|
||
<el-descriptions-item label="镜片厂">
|
||
<el-tag
|
||
v-if="isPendingTagText(formatLensFactory(detail))"
|
||
type="danger"
|
||
size="small"
|
||
:disable-transitions="true"
|
||
>{{ formatLensFactory(detail) }}</el-tag>
|
||
<span v-else>{{ formatLensFactory(detail) }}</span>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="通用镜片">{{ formatLens(detail) }}</el-descriptions-item>
|
||
<el-descriptions-item label="采购结算">
|
||
<dict-tag :options="dict.type.jy_purchase_settle_status" :value="detail.purchaseSettleStatus" />
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="销售结算">
|
||
<dict-tag :options="dict.type.jy_sale_settle_status" :value="detail.saleSettleStatus" />
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">02</span>
|
||
<div class="section-text">
|
||
<h4>收货信息</h4>
|
||
<p>镜片寄送地址与联系方式</p>
|
||
</div>
|
||
</div>
|
||
<div class="section-body">
|
||
<el-descriptions :column="2" border size="small" class="detail-descriptions">
|
||
<el-descriptions-item label="收货人">{{ detail.receiverName || '-' }}</el-descriptions-item>
|
||
<el-descriptions-item label="手机号">{{ detail.receiverPhone || '-' }}</el-descriptions-item>
|
||
<el-descriptions-item label="收货地址" :span="2">{{ detail.receiverAddress || '-' }}</el-descriptions-item>
|
||
</el-descriptions>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">03</span>
|
||
<div class="section-text">
|
||
<h4>价格与结算</h4>
|
||
<p>价格信息及合计金额</p>
|
||
</div>
|
||
</div>
|
||
<div class="section-body">
|
||
<el-descriptions :column="2" border size="small" class="detail-descriptions detail-descriptions--price">
|
||
<el-descriptions-item label="B价格">
|
||
<el-tag
|
||
v-if="isPendingTagText(formatPriceAmount(formatPriceB(detail)))"
|
||
type="danger"
|
||
size="small"
|
||
:disable-transitions="true"
|
||
>{{ formatPriceAmount(formatPriceB(detail)) }}</el-tag>
|
||
<span v-else>{{ formatPriceAmount(formatPriceB(detail)) }}</span>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="C价格">
|
||
<el-tag
|
||
v-if="isPendingTagText(formatPriceAmount(formatPriceC(detail)))"
|
||
type="danger"
|
||
size="small"
|
||
:disable-transitions="true"
|
||
>{{ formatPriceAmount(formatPriceC(detail)) }}</el-tag>
|
||
<span v-else>{{ formatPriceAmount(formatPriceC(detail)) }}</span>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="物流费用">{{ formatPriceAmount(formatDetailLogisticsFee(detail)) }}</el-descriptions-item>
|
||
<el-descriptions-item label="渐进多焦点">{{ detail.progressiveMultifocal === 1 ? '是' : '否' }}</el-descriptions-item>
|
||
<el-descriptions-item v-if="detail.progressiveMultifocal === 1" label="渐进多焦点价格">
|
||
<el-tag
|
||
v-if="isPendingTagText(formatPriceAmount(formatProgressiveMultifocalPrice(detail)))"
|
||
type="danger"
|
||
size="small"
|
||
:disable-transitions="true"
|
||
>{{ formatPriceAmount(formatProgressiveMultifocalPrice(detail)) }}</el-tag>
|
||
<span v-else>{{ formatPriceAmount(formatProgressiveMultifocalPrice(detail)) }}</span>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="B合计">
|
||
<el-tag
|
||
v-if="isPendingTagText(formatPriceAmount(formatDetailPriceTotal(detail, 'priceB')))"
|
||
type="danger"
|
||
size="small"
|
||
:disable-transitions="true"
|
||
>{{ formatPriceAmount(formatDetailPriceTotal(detail, 'priceB')) }}</el-tag>
|
||
<span v-else class="price-total-value">{{ formatPriceAmount(formatDetailPriceTotal(detail, 'priceB')) }}</span>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="C合计">
|
||
<el-tag
|
||
v-if="isPendingTagText(formatPriceAmount(formatDetailPriceTotal(detail, 'priceC')))"
|
||
type="danger"
|
||
size="small"
|
||
:disable-transitions="true"
|
||
>{{ formatPriceAmount(formatDetailPriceTotal(detail, 'priceC')) }}</el-tag>
|
||
<span v-else class="price-total-value">{{ formatPriceAmount(formatDetailPriceTotal(detail, 'priceC')) }}</span>
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
<div class="detail-logistics-fee-block">
|
||
<el-table :data="detailLogisticsLogList" class="lens-detail-table detail-logistics-fee-table" size="small">
|
||
<el-table-column label="物流公司" align="center" prop="expressCompany" min-width="120" show-overflow-tooltip />
|
||
<el-table-column label="物流单号" align="center" prop="expressNo" min-width="160" show-overflow-tooltip />
|
||
<el-table-column label="物流费用" align="center" width="100">
|
||
<template slot-scope="scope">
|
||
<span>{{ formatPriceAmount(formatLogisticsLogFee(scope.row, detail)) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="发货日期" align="center" width="120">
|
||
<template slot-scope="scope">
|
||
<span>{{ formatShipDate(scope.row.operateTime) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
<div v-if="!detailLogisticsLogList.length" class="detail-empty-tip">暂无物流费用记录</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">04</span>
|
||
<div class="section-text">
|
||
<h4>附件与备注</h4>
|
||
<p>订单相关资料与补充说明</p>
|
||
</div>
|
||
</div>
|
||
<div class="section-body">
|
||
<el-descriptions :column="2" border size="small" class="detail-descriptions">
|
||
<el-descriptions-item label="附件" :span="2">
|
||
<template v-if="parseAttachment(detail.attachment).length">
|
||
<template v-for="(url, index) in parseAttachment(detail.attachment)">
|
||
<el-link
|
||
v-if="isAttachmentImage(url)"
|
||
:key="'preview-' + index"
|
||
type="primary"
|
||
class="detail-attachment-link"
|
||
@click="handleAttachmentPreview(url)"
|
||
>{{ getAttachmentName(url) }}</el-link>
|
||
<el-link
|
||
v-else
|
||
:key="'link-' + index"
|
||
:href="getAttachmentUrl(url)"
|
||
target="_blank"
|
||
type="primary"
|
||
class="detail-attachment-link"
|
||
>{{ getAttachmentName(url) }}</el-link>
|
||
</template>
|
||
</template>
|
||
<span v-else>-</span>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="备注" :span="2">{{ detail.remark || '-' }}</el-descriptions-item>
|
||
</el-descriptions>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="lens-form-section lens-form-section--optometry">
|
||
<div class="section-head">
|
||
<span class="section-index">05</span>
|
||
<div class="section-text">
|
||
<h4>验光参数</h4>
|
||
<p>左右眼验光数据明细</p>
|
||
</div>
|
||
</div>
|
||
<div class="section-body">
|
||
<el-table
|
||
:data="detailOptometryList"
|
||
:span-method="detailOptometrySpanMethod"
|
||
class="lens-optometry-table"
|
||
size="small"
|
||
>
|
||
<el-table-column label="左右" align="center" width="100">
|
||
<template slot-scope="scope">
|
||
<span>{{ scope.row.eyeSide === 'OS' ? '左眼(OS)' : '右眼(OD)' }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="球镜S(度)" align="center" min-width="90">
|
||
<template slot-scope="scope">
|
||
<span>{{ formatDetailOptometryDecimal(scope.row.sphereS) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="柱镜C(度)" align="center" min-width="90">
|
||
<template slot-scope="scope">
|
||
<span>{{ formatDetailOptometryDecimal(scope.row.cylinderC) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column align="center" min-width="80">
|
||
<template slot="header">
|
||
<span>轴位A(度)</span>
|
||
</template>
|
||
<template slot-scope="scope">
|
||
<span>{{ scope.row.axisA != null ? scope.row.axisA : '-' }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="瞳距(mm)" align="center" min-width="90">
|
||
<template slot-scope="scope">
|
||
<span>{{ formatDetailPdValue(scope.row, scope.$index) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column v-if="detail.progressiveMultifocal === 1" label="瞳高(mm)" align="center" min-width="80">
|
||
<template slot-scope="scope">
|
||
<span>{{ scope.row.pupilHeight != null ? scope.row.pupilHeight : '-' }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="远用VA(视力值)" align="center" min-width="90">
|
||
<template slot-scope="scope">
|
||
<span>{{ scope.row.distanceVa != null && scope.row.distanceVa !== '' ? scope.row.distanceVa : '-' }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column v-if="detail.progressiveMultifocal === 1" label="近用ADD(屈光度)" align="center" min-width="100">
|
||
<template slot-scope="scope">
|
||
<span>{{ formatDetailNearAdd(scope.row.nearAdd) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">06</span>
|
||
<div class="section-text">
|
||
<h4>状态变更记录</h4>
|
||
<p>订单全流程状态流转轨迹</p>
|
||
</div>
|
||
</div>
|
||
<div class="section-body">
|
||
<el-table :data="detail.statusLogList || []" class="lens-detail-table" size="small">
|
||
<el-table-column label="订单状态" align="center" prop="orderStatus" width="120">
|
||
<template slot-scope="scope">
|
||
<dict-tag :options="dict.type.jy_order_status" :value="scope.row.orderStatus" />
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="备注" align="center" prop="remark" min-width="160" show-overflow-tooltip />
|
||
<el-table-column label="操作人" align="center" prop="operator" width="100" />
|
||
<el-table-column label="操作时间" align="center" prop="operateTime" width="160" />
|
||
</el-table>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<el-dialog :visible.sync="attachmentPreviewVisible" title="图片预览" width="800px" append-to-body>
|
||
<img :src="attachmentPreviewUrl" style="max-width: 100%; display: block; margin: 0 auto;" />
|
||
</el-dialog>
|
||
|
||
<el-dialog
|
||
:visible.sync="logisticsDialogVisible"
|
||
width="720px"
|
||
append-to-body
|
||
custom-class="lens-order-detail-dialog"
|
||
>
|
||
<div slot="title" class="lens-dialog-header">
|
||
<div class="lens-dialog-title-wrap">
|
||
<h3 class="lens-dialog-title">物流信息</h3>
|
||
<p class="lens-dialog-subtitle">{{ logisticsDialogSubtitle }}</p>
|
||
</div>
|
||
</div>
|
||
<div class="lens-order-detail">
|
||
<section v-if="logisticsBasic" class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">01</span>
|
||
<div class="section-text">
|
||
<h4>物流概要</h4>
|
||
<p>订单关联的物流公司与单号</p>
|
||
</div>
|
||
</div>
|
||
<div class="section-body">
|
||
<el-descriptions :column="1" border size="small" class="detail-descriptions">
|
||
<el-descriptions-item label="订单编号">{{ logisticsBasic.orderNo }}</el-descriptions-item>
|
||
<el-descriptions-item label="物流公司">{{ logisticsBasic.expressCompany }}</el-descriptions-item>
|
||
<el-descriptions-item label="物流单号">{{ logisticsBasic.expressNo }}</el-descriptions-item>
|
||
</el-descriptions>
|
||
</div>
|
||
</section>
|
||
<section class="lens-form-section">
|
||
<div class="section-head">
|
||
<span class="section-index">02</span>
|
||
<div class="section-text">
|
||
<h4>物流轨迹</h4>
|
||
<p>最新物流动态与时间记录</p>
|
||
</div>
|
||
</div>
|
||
<div class="section-body">
|
||
<div v-if="logisticsDetail && logisticsDetail.traces && logisticsDetail.traces.length > 0" class="logistics-traces">
|
||
<el-timeline>
|
||
<el-timeline-item
|
||
v-for="(item, idx) in logisticsDetail.traces"
|
||
:key="idx"
|
||
:timestamp="item.timeDesc || ''"
|
||
>
|
||
{{ item.line }}
|
||
</el-timeline-item>
|
||
</el-timeline>
|
||
</div>
|
||
<div v-else class="detail-empty-tip">未查到物流轨迹</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
<div slot="footer" class="lens-dialog-footer">
|
||
<el-button class="lens-btn-ghost" @click="logisticsDialogVisible = false">关 闭</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<el-dialog title="生成费用结算单" :visible.sync="settlementGenerateOpen" width="480px" append-to-body>
|
||
<el-form ref="settlementGenerateForm" :model="settlementGenerateForm" :rules="settlementGenerateRules" label-width="100px">
|
||
<el-form-item label="结算年月" prop="settleYearMonth">
|
||
<el-date-picker
|
||
v-model="settlementGenerateForm.settleYearMonth"
|
||
type="month"
|
||
value-format="yyyy-MM"
|
||
placeholder="选择年月"
|
||
style="width: 100%"
|
||
/>
|
||
</el-form-item>
|
||
<el-alert
|
||
title="仅汇总所选年月内已完成或换货完成状态的订单;品牌方生成应收(AR),镜片厂生成应付(AP)。"
|
||
type="info"
|
||
:closable="false"
|
||
show-icon
|
||
/>
|
||
</el-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button @click="settlementGenerateOpen = false">取 消</el-button>
|
||
<el-button type="primary" :loading="settlementGenerateLoading" @click="submitGenerateSettlement">确 定</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import axios from 'axios'
|
||
import { getToken } from '@/utils/auth'
|
||
import { isExternal } from '@/utils/validate'
|
||
import { listOrder, getOrder, getOrderLogistics, delOrder, addOrder, updateOrder, previewAssignPrice, assignOrder, rejectOrder, closeOrder, completeOrder, agreeExchangeOrder, rejectExchangeOrder, changeOrderStatus } from "@/api/jysystem/order";
|
||
import { checkPermi } from "@/utils/permission";
|
||
import { listBrandTenant, listLensFactoryTenant } from "@/api/jysystem/tenant";
|
||
import { listLensOptions } from "@/api/jysystem/lens";
|
||
import { checkFeeSettlement, generateFeeSettlement } from "@/api/jysystem/feeSettlement";
|
||
|
||
export default {
|
||
name: "Order",
|
||
dicts: ['jy_order_status', 'jy_purchase_settle_status', 'jy_sale_settle_status'],
|
||
data() {
|
||
return {
|
||
loading: true,
|
||
ids: [],
|
||
single: true,
|
||
multiple: true,
|
||
showSearch: true,
|
||
total: 0,
|
||
orderList: [],
|
||
brandTenantList: [],
|
||
lensFactoryList: [],
|
||
assignLensFactoryList: [],
|
||
lensList: [],
|
||
title: "",
|
||
open: false,
|
||
detailOpen: false,
|
||
detail: {},
|
||
detailPdMode: 'single',
|
||
PD_TYPE_SINGLE: '1',
|
||
PD_TYPE_DUAL: '2',
|
||
OPTOMETRY_PD_COLUMN_INDEX: 4,
|
||
assignOpen: false,
|
||
assignLoading: false,
|
||
assignDialogKey: 0,
|
||
assignDialogToken: 0,
|
||
assignForm: {
|
||
orderId: null,
|
||
orderNo: null,
|
||
lensId: null,
|
||
lensText: '',
|
||
progressiveMultifocal: 0,
|
||
lensFactoryTenantId: null
|
||
},
|
||
assignPreview: {},
|
||
assignRules: {
|
||
lensFactoryTenantId: [{ required: true, message: '请选择镜片厂', trigger: 'change' }]
|
||
},
|
||
rejectOpen: false,
|
||
rejectLoading: false,
|
||
rejectForm: {
|
||
orderId: null,
|
||
orderNo: '',
|
||
reason: ''
|
||
},
|
||
rejectRules: {
|
||
reason: [{ required: true, message: '请输入驳回原因', trigger: 'blur' }]
|
||
},
|
||
exchangeRejectOpen: false,
|
||
exchangeRejectLoading: false,
|
||
exchangeRejectForm: {
|
||
orderId: null,
|
||
orderNo: '',
|
||
reason: ''
|
||
},
|
||
exchangeRejectRules: {
|
||
reason: [{ required: true, message: '请输入拒绝换货申请原因', trigger: 'blur' }]
|
||
},
|
||
ORDER_STATUS_DRAFT: '1',
|
||
ORDER_STATUS_SUBMITTED: '2',
|
||
ORDER_STATUS_REJECTED: '5',
|
||
ORDER_STATUS_CANCELLED: '18',
|
||
ORDER_STATUS_WITHDRAWN: '20',
|
||
ORDER_STATUS_SHIPPED: '8',
|
||
ORDER_STATUS_COMPLETED: '9',
|
||
ORDER_STATUS_EXCHANGE_APPLY: '12',
|
||
ORDER_STATUS_EXCHANGE_AGREED: '13',
|
||
ORDER_STATUS_EXCHANGE_LOGISTICS: '15',
|
||
ORDER_STATUS_EXCHANGE_COMPLETED: '17',
|
||
ORDER_STATUS_EXCHANGE_REJECTED: '21',
|
||
logisticsDialogVisible: false,
|
||
logisticsBasic: null,
|
||
logisticsDetail: null,
|
||
attachmentPreviewVisible: false,
|
||
attachmentPreviewUrl: '',
|
||
settlementGenerateOpen: false,
|
||
settlementGenerateLoading: false,
|
||
settlementGenerateForm: {
|
||
settleYearMonth: undefined
|
||
},
|
||
settlementGenerateRules: {
|
||
settleYearMonth: [{ required: true, message: '请选择结算年月', trigger: 'change' }]
|
||
},
|
||
activeQuickFilter: null,
|
||
queryParams: {
|
||
pageNum: 1,
|
||
pageSize: 10,
|
||
orderNo: null,
|
||
brandTenantId: null,
|
||
lensFactoryTenantId: null,
|
||
orderStatus: null,
|
||
orderStatusIn: null,
|
||
purchaseSettleStatus: null,
|
||
saleSettleStatus: null,
|
||
receiverName: null
|
||
},
|
||
form: {},
|
||
rules: {},
|
||
baseUrl: process.env.VUE_APP_BASE_API,
|
||
attachmentFileTypes: ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'pdf', 'png', 'jpg', 'jpeg', 'zip']
|
||
};
|
||
},
|
||
computed: {
|
||
formDialogSubtitle() {
|
||
if (this.form && this.form.id) {
|
||
return '更新订单完整信息、价格结算与验光参数';
|
||
}
|
||
return '填写订单信息、价格结算与验光参数';
|
||
},
|
||
detailDialogSubtitle() {
|
||
if (this.detail && this.detail.orderNo) {
|
||
return `订单编号 ${this.detail.orderNo} · 查看订单完整信息与流转记录`;
|
||
}
|
||
return '查看订单完整信息、价格结算与流转记录';
|
||
},
|
||
logisticsDialogSubtitle() {
|
||
if (this.logisticsBasic && this.logisticsBasic.orderNo) {
|
||
return `订单编号 ${this.logisticsBasic.orderNo} · 查看物流公司与轨迹信息`;
|
||
}
|
||
return '查看物流公司与轨迹信息';
|
||
},
|
||
assignDialogSubtitle() {
|
||
if (this.assignForm && this.assignForm.orderNo) {
|
||
return `订单编号 ${this.assignForm.orderNo} · 选择镜片厂并确认分配价格`;
|
||
}
|
||
return '选择镜片厂并确认分配价格';
|
||
},
|
||
hasAssignPreview() {
|
||
const preview = this.assignPreview || {};
|
||
return preview.priceB != null
|
||
|| preview.priceC != null
|
||
|| (this.assignForm.progressiveMultifocal === 1 && preview.progressiveMultifocalPrice != null);
|
||
},
|
||
detailPdLabel() {
|
||
return this.detailPdMode === 'single' ? '单瞳距' : '瞳距';
|
||
},
|
||
detailLogisticsLogList() {
|
||
return this.buildDetailLogisticsLogList(this.detail);
|
||
},
|
||
detailOptometryList() {
|
||
return this.sortOptometryList((this.detail && this.detail.optometryList) || []);
|
||
},
|
||
canEditOrderStatus() {
|
||
return checkPermi(['jysystem:order:edit']);
|
||
}
|
||
},
|
||
created() {
|
||
this.getList();
|
||
this.loadBrandTenants();
|
||
this.loadLensFactoryList();
|
||
this.loadLensList();
|
||
},
|
||
methods: {
|
||
getList() {
|
||
this.loading = true;
|
||
listOrder(this.queryParams).then(response => {
|
||
this.orderList = response.rows;
|
||
this.total = response.total;
|
||
this.loading = false;
|
||
});
|
||
},
|
||
loadBrandTenants() {
|
||
listBrandTenant().then(response => {
|
||
this.brandTenantList = response.data || [];
|
||
});
|
||
},
|
||
loadLensFactoryList() {
|
||
listLensFactoryTenant().then(response => {
|
||
this.lensFactoryList = response.data || [];
|
||
});
|
||
},
|
||
loadLensList() {
|
||
listLensOptions().then(response => {
|
||
this.lensList = response.data || [];
|
||
});
|
||
},
|
||
isPendingTagText(text) {
|
||
return text === '未分配' || text === '未核算';
|
||
},
|
||
formatLensOption(item) {
|
||
if (!item) return '-';
|
||
const name = item.productName || '';
|
||
const material = item.material || '';
|
||
return material ? `${name}(${material})` : name;
|
||
},
|
||
formatProduct(row) {
|
||
if (!row) {
|
||
return '-';
|
||
}
|
||
if (row.productModel || row.productName) {
|
||
const model = row.productModel || '';
|
||
const name = row.productName || '';
|
||
return model ? `${model}(${name})` : name || '-';
|
||
}
|
||
return '-';
|
||
},
|
||
formatLens(row) {
|
||
if (!row) {
|
||
return '-';
|
||
}
|
||
if (row.lensProductName || row.lensMaterial) {
|
||
return this.formatLensOption({ productName: row.lensProductName, material: row.lensMaterial });
|
||
}
|
||
return '-';
|
||
},
|
||
isPendingAssign(row) {
|
||
if (!row) return false;
|
||
const status = String(row.orderStatus);
|
||
return status === this.ORDER_STATUS_DRAFT
|
||
|| status === this.ORDER_STATUS_SUBMITTED
|
||
|| status === this.ORDER_STATUS_REJECTED
|
||
|| status === this.ORDER_STATUS_CANCELLED
|
||
|| status === this.ORDER_STATUS_WITHDRAWN;
|
||
},
|
||
formatLensFactory(row) {
|
||
if (!row) return '-';
|
||
if (this.isPendingAssign(row)) return '未分配';
|
||
return row.lensFactoryTenantName || '-';
|
||
},
|
||
formatPriceB(row) {
|
||
if (!row) return '-';
|
||
if (this.isExchangeOrder(row)) return '-';
|
||
if (this.isPendingAssign(row)) return '未核算';
|
||
return row.priceB != null ? row.priceB : '-';
|
||
},
|
||
formatPriceC(row) {
|
||
if (!row) return '-';
|
||
if (this.isExchangeOrder(row)) return '-';
|
||
if (this.isPendingAssign(row)) return '未核算';
|
||
return row.priceC != null ? row.priceC : '-';
|
||
},
|
||
formatProgressiveMultifocalPrice(row) {
|
||
if (!row) return '-';
|
||
if (this.isExchangeOrder(row)) return '-';
|
||
if (Number(row.progressiveMultifocal) !== 1) return '-';
|
||
if (this.isPendingAssign(row)) return '未核算';
|
||
return row.progressiveMultifocalPrice != null ? row.progressiveMultifocalPrice : '-';
|
||
},
|
||
isExchangeOrder(row) {
|
||
if (!row) return false;
|
||
if (row.orderNo && String(row.orderNo).startsWith('HH')) return true;
|
||
const status = row.orderStatus != null ? String(row.orderStatus) : '';
|
||
return status === this.ORDER_STATUS_EXCHANGE_APPLY
|
||
|| status === this.ORDER_STATUS_EXCHANGE_AGREED
|
||
|| status === this.ORDER_STATUS_EXCHANGE_LOGISTICS
|
||
|| status === this.ORDER_STATUS_EXCHANGE_COMPLETED;
|
||
},
|
||
formatDetailPriceTotal(detail, priceKey) {
|
||
if (this.isExchangeOrder(detail)) return this.formatDetailLogisticsFee(detail);
|
||
return this.formatPriceTotal(detail, priceKey);
|
||
},
|
||
formatLogisticsFee(row) {
|
||
if (!row) return '-';
|
||
if (!this.isExchangeOrder(row)) return '-';
|
||
const fee = this.parseLogisticsFeeValue(row.logisticsFee);
|
||
return fee != null ? fee : '-';
|
||
},
|
||
formatPriceBC(row) {
|
||
return `${this.formatPriceB(row)} / ${this.formatPriceC(row)}`;
|
||
},
|
||
formatPriceAmount(value) {
|
||
if (value == null || value === '' || value === '-') return '-';
|
||
if (value === '未核算') return '未核算';
|
||
const num = Number(value);
|
||
if (Number.isNaN(num)) return value;
|
||
return num.toFixed(2);
|
||
},
|
||
buildDetailLogisticsLogList(detail) {
|
||
const list = (detail && detail.statusLogList) || [];
|
||
return list
|
||
.filter(item => item.expressNo != null && String(item.expressNo).trim() !== '')
|
||
.sort((a, b) => {
|
||
const timeA = a.operateTime ? new Date(a.operateTime).getTime() : 0;
|
||
const timeB = b.operateTime ? new Date(b.operateTime).getTime() : 0;
|
||
return timeB - timeA;
|
||
});
|
||
},
|
||
parseLogisticsFeeValue(value) {
|
||
if (value == null || value === '') return null;
|
||
const num = Number(value);
|
||
return Number.isNaN(num) ? null : num;
|
||
},
|
||
formatLogisticsLogFee(log, detail) {
|
||
if (!log) return '-';
|
||
const fee = this.parseLogisticsFeeValue(log.logisticsFee);
|
||
if (fee != null) return fee;
|
||
const logs = this.buildDetailLogisticsLogList(detail);
|
||
if (logs.length === 1 && detail && detail.logisticsFee != null) {
|
||
const legacyFee = this.parseLogisticsFeeValue(detail.logisticsFee);
|
||
if (legacyFee != null) return legacyFee;
|
||
}
|
||
return '-';
|
||
},
|
||
sumDetailLogisticsFee(detail) {
|
||
if (!detail) return '-';
|
||
const logs = this.buildDetailLogisticsLogList(detail);
|
||
let sum = 0;
|
||
let hasFee = false;
|
||
logs.forEach(log => {
|
||
const fee = this.parseLogisticsFeeValue(log.logisticsFee);
|
||
if (fee != null) {
|
||
sum += fee;
|
||
hasFee = true;
|
||
}
|
||
});
|
||
if (!hasFee && detail.logisticsFee != null) {
|
||
const legacyFee = this.parseLogisticsFeeValue(detail.logisticsFee);
|
||
if (legacyFee != null) return legacyFee;
|
||
}
|
||
if (!hasFee) return '-';
|
||
return sum;
|
||
},
|
||
formatDetailLogisticsFee(detail) {
|
||
return this.sumDetailLogisticsFee(detail);
|
||
},
|
||
formatShipDate(time) {
|
||
if (!time) {
|
||
return '-';
|
||
}
|
||
const text = String(time);
|
||
return text.length >= 10 ? text.substring(0, 10) : text;
|
||
},
|
||
formatPriceTotal(row, priceKey) {
|
||
if (!row) return '-';
|
||
if (this.isPendingAssign(row)) return '未核算';
|
||
const base = row[priceKey] != null ? Number(row[priceKey]) : 0;
|
||
const logisticsRaw = this.sumDetailLogisticsFee(row);
|
||
const logistics = logisticsRaw === '-' ? 0 : Number(logisticsRaw);
|
||
const pmf = row.progressiveMultifocalPrice != null ? Number(row.progressiveMultifocalPrice) : 0;
|
||
if ([base, logistics, pmf].some(value => Number.isNaN(value))) return '-';
|
||
return (base + logistics + pmf).toFixed(2);
|
||
},
|
||
parseAttachment(attachment) {
|
||
if (!attachment) return [];
|
||
return String(attachment).split(',').map(item => item.trim()).filter(item => item !== '');
|
||
},
|
||
getAttachmentName(url) {
|
||
if (!url) return '';
|
||
const index = url.lastIndexOf('/');
|
||
return index > -1 ? url.slice(index + 1) : url;
|
||
},
|
||
getAttachmentUrl(url) {
|
||
if (!url) return '';
|
||
if (isExternal(url)) return url;
|
||
return this.baseUrl + url;
|
||
},
|
||
isAttachmentImage(url) {
|
||
const fileName = this.getAttachmentName(url);
|
||
const ext = (fileName.split('.').pop() || '').toLowerCase();
|
||
return ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'svg'].includes(ext);
|
||
},
|
||
handleAttachmentPreview(url) {
|
||
this.attachmentPreviewUrl = this.getAttachmentUrl(url);
|
||
this.attachmentPreviewVisible = true;
|
||
},
|
||
sortOptometryList(list) {
|
||
const order = { OS: 0, OD: 1 };
|
||
return [...list].sort((a, b) => {
|
||
const aOrder = order[a.eyeSide] != null ? order[a.eyeSide] : 99;
|
||
const bOrder = order[b.eyeSide] != null ? order[b.eyeSide] : 99;
|
||
return aOrder - bOrder;
|
||
});
|
||
},
|
||
createDefaultOptometryList() {
|
||
return [
|
||
{ eyeSide: 'OS', sphereS: 0, cylinderC: null, axisA: null, pd: null, dualPd: null, pupilHeight: null, distanceVa: null, nearAdd: null },
|
||
{ eyeSide: 'OD', sphereS: 0, cylinderC: null, axisA: null, pd: null, dualPd: null, pupilHeight: null, distanceVa: null, nearAdd: null }
|
||
];
|
||
},
|
||
detectPdMode(optometryList) {
|
||
if (!optometryList || !optometryList.length) {
|
||
return 'single';
|
||
}
|
||
const pdType = optometryList[0].pdType;
|
||
if (pdType === this.PD_TYPE_DUAL) return 'dual';
|
||
if (pdType === this.PD_TYPE_SINGLE) return 'single';
|
||
const hasDual = optometryList.some(item => item.dualPd != null);
|
||
return hasDual ? 'dual' : 'single';
|
||
},
|
||
detailOptometrySpanMethod({ rowIndex, columnIndex }) {
|
||
if (columnIndex !== this.OPTOMETRY_PD_COLUMN_INDEX || this.detailPdMode !== 'single') {
|
||
return { rowspan: 1, colspan: 1 };
|
||
}
|
||
if (rowIndex === 0) {
|
||
return { rowspan: 2, colspan: 1 };
|
||
}
|
||
return { rowspan: 0, colspan: 0 };
|
||
},
|
||
formatDetailPdValue(row, rowIndex) {
|
||
if (!row) return '-';
|
||
if (this.detailPdMode === 'dual') {
|
||
return row.dualPd != null ? row.dualPd : '-';
|
||
}
|
||
if (rowIndex > 0) return '';
|
||
const list = this.detailOptometryList;
|
||
const pdRow = list.find(item => item.pd != null) || list[0];
|
||
return pdRow && pdRow.pd != null ? pdRow.pd : '-';
|
||
},
|
||
formatDetailOptometryDecimal(value) {
|
||
if (value == null || value === '') return '-';
|
||
const num = Number(value);
|
||
if (Number.isNaN(num)) return String(value);
|
||
return num.toFixed(2);
|
||
},
|
||
formatDetailNearAdd(value) {
|
||
if (value == null || value === '') return '-';
|
||
const num = Number(value);
|
||
if (Number.isNaN(num)) return String(value);
|
||
return '+' + num.toFixed(2);
|
||
},
|
||
isAxisAEditable(row) {
|
||
const val = row && row.cylinderC;
|
||
if (val == null || val === '') return false;
|
||
const num = Number(val);
|
||
return !Number.isNaN(num) && num !== 0;
|
||
},
|
||
getSphereSign(sphereS) {
|
||
if (sphereS == null || sphereS === '') return 0;
|
||
const num = Number(sphereS);
|
||
if (Number.isNaN(num) || num === 0) return 0;
|
||
return num > 0 ? 1 : -1;
|
||
},
|
||
getCylinderCMin(row) {
|
||
return this.getSphereSign(row && row.sphereS) > 0 ? 0 : -10;
|
||
},
|
||
getCylinderCMax(row) {
|
||
return this.getSphereSign(row && row.sphereS) < 0 ? 0 : 10;
|
||
},
|
||
alignCylinderSignWithSphere(row) {
|
||
if (!row || row.cylinderC == null || row.cylinderC === '') return;
|
||
let cylinder = Number(row.cylinderC);
|
||
if (Number.isNaN(cylinder) || cylinder === 0) return;
|
||
const sphereSign = this.getSphereSign(row.sphereS);
|
||
if (sphereSign > 0 && cylinder < 0) cylinder = Math.abs(cylinder);
|
||
else if (sphereSign < 0 && cylinder > 0) cylinder = -Math.abs(cylinder);
|
||
row.cylinderC = Math.min(this.getCylinderCMax(row), Math.max(this.getCylinderCMin(row), cylinder));
|
||
},
|
||
onSphereSChange(val, row) {
|
||
this.alignCylinderSignWithSphere(row);
|
||
if (!this.isAxisAEditable(row)) row.axisA = null;
|
||
},
|
||
onCylinderCChange(val, row) {
|
||
if (val == null || val === '' || Number(val) === 0) {
|
||
row.axisA = null;
|
||
return;
|
||
}
|
||
this.alignCylinderSignWithSphere(row);
|
||
if (!this.isAxisAEditable(row)) row.axisA = null;
|
||
},
|
||
cancel() {
|
||
this.open = false;
|
||
this.reset();
|
||
},
|
||
handleProgressiveMultifocalChange(value) {
|
||
if (Number(value) !== 1) {
|
||
this.form.progressiveMultifocalPrice = 0;
|
||
if (this.form.optometryList) {
|
||
this.form.optometryList.forEach(row => {
|
||
row.nearAdd = null;
|
||
row.pupilHeight = null;
|
||
});
|
||
}
|
||
return;
|
||
}
|
||
if (!this.form.lensFactoryTenantId) {
|
||
this.$modal.msgWarning("请先选择镜片厂");
|
||
this.form.progressiveMultifocalPrice = 0;
|
||
return;
|
||
}
|
||
this.refreshFormPricesByFactory(this.form.lensFactoryTenantId, { progressiveOnly: true });
|
||
},
|
||
handleFormLensFactoryChange(lensFactoryTenantId) {
|
||
this.refreshFormPricesByFactory(lensFactoryTenantId);
|
||
},
|
||
refreshFormPricesByFactory(lensFactoryTenantId, options = {}) {
|
||
const progressiveOnly = options.progressiveOnly === true;
|
||
if (!lensFactoryTenantId) {
|
||
if (!progressiveOnly) {
|
||
this.form.priceB = 0;
|
||
this.form.priceC = 0;
|
||
}
|
||
this.form.progressiveMultifocalPrice = 0;
|
||
return;
|
||
}
|
||
if (!this.form.id) {
|
||
if (Number(this.form.progressiveMultifocal) === 1) {
|
||
this.form.progressiveMultifocalPrice = this.getProgressiveMultifocalPriceByFactory(lensFactoryTenantId);
|
||
}
|
||
return;
|
||
}
|
||
previewAssignPrice(this.form.id, lensFactoryTenantId).then(response => {
|
||
this.applyAssignPreviewPrices(response.data || {}, { progressiveOnly });
|
||
}).catch(() => {
|
||
if (!progressiveOnly) {
|
||
this.form.priceB = 0;
|
||
this.form.priceC = 0;
|
||
}
|
||
this.form.progressiveMultifocalPrice = 0;
|
||
this.$modal.msgWarning("未能获取该镜片厂价格,请确认镜片厂已配置对应镜片价格");
|
||
});
|
||
},
|
||
applyAssignPreviewPrices(preview, options = {}) {
|
||
const progressiveOnly = options.progressiveOnly === true;
|
||
if (!progressiveOnly) {
|
||
if (preview.priceB != null) {
|
||
this.form.priceB = Number(preview.priceB);
|
||
}
|
||
if (preview.priceC != null) {
|
||
this.form.priceC = Number(preview.priceC);
|
||
}
|
||
}
|
||
if (Number(this.form.progressiveMultifocal) === 1) {
|
||
if (preview.progressiveMultifocalPrice != null) {
|
||
this.form.progressiveMultifocalPrice = Number(preview.progressiveMultifocalPrice);
|
||
} else {
|
||
this.form.progressiveMultifocalPrice = this.getProgressiveMultifocalPriceByFactory(this.form.lensFactoryTenantId);
|
||
}
|
||
} else {
|
||
this.form.progressiveMultifocalPrice = 0;
|
||
}
|
||
},
|
||
getProgressiveMultifocalPriceByFactory(lensFactoryTenantId) {
|
||
if (lensFactoryTenantId == null || lensFactoryTenantId === "") {
|
||
return 0;
|
||
}
|
||
const factory = (this.lensFactoryList || []).find(item => String(item.id) === String(lensFactoryTenantId));
|
||
if (!factory || factory.progressiveMultifocalPrice == null) {
|
||
return 0;
|
||
}
|
||
const num = Number(factory.progressiveMultifocalPrice);
|
||
return Number.isNaN(num) ? 0 : num;
|
||
},
|
||
resolveProgressiveMultifocalPrice() {
|
||
const price = this.form.progressiveMultifocalPrice;
|
||
if (price != null && Number(price) > 0) {
|
||
return Number(price);
|
||
}
|
||
return this.getProgressiveMultifocalPriceByFactory(this.form.lensFactoryTenantId);
|
||
},
|
||
reset() {
|
||
this.form = {
|
||
id: null,
|
||
orderNo: null,
|
||
brandTenantId: null,
|
||
lensFactoryTenantId: null,
|
||
lensId: null,
|
||
progressiveMultifocal: 0,
|
||
progressiveMultifocalPrice: 0,
|
||
priceB: 0,
|
||
priceC: 0,
|
||
logisticsFee: null,
|
||
orderStatus: '1',
|
||
purchaseSettleStatus: '0',
|
||
saleSettleStatus: '0',
|
||
receiverName: null,
|
||
receiverPhone: null,
|
||
receiverAddress: null,
|
||
attachment: null,
|
||
remark: null,
|
||
optometryList: this.createDefaultOptometryList()
|
||
};
|
||
this.resetForm("form");
|
||
},
|
||
handleQuery() {
|
||
this.queryParams.pageNum = 1;
|
||
this.getList();
|
||
},
|
||
handleOrderStatusChange() {
|
||
this.activeQuickFilter = null;
|
||
this.queryParams.orderStatusIn = null;
|
||
},
|
||
handleQuickFilter(type) {
|
||
if (this.activeQuickFilter === type) {
|
||
this.activeQuickFilter = null;
|
||
this.queryParams.orderStatusIn = null;
|
||
} else {
|
||
this.activeQuickFilter = type;
|
||
this.queryParams.orderStatus = null;
|
||
if (type === 'pendingAssign') {
|
||
this.queryParams.orderStatusIn = `${this.ORDER_STATUS_SUBMITTED},${this.ORDER_STATUS_WITHDRAWN}`;
|
||
} else if (type === 'exchangeApply') {
|
||
this.queryParams.orderStatusIn = this.ORDER_STATUS_EXCHANGE_APPLY;
|
||
} else if (type === 'exchangeRejected') {
|
||
this.queryParams.orderStatusIn = this.ORDER_STATUS_EXCHANGE_REJECTED;
|
||
}
|
||
}
|
||
this.handleQuery();
|
||
},
|
||
resetQuery() {
|
||
this.resetForm("queryForm");
|
||
this.activeQuickFilter = null;
|
||
this.queryParams.orderStatusIn = null;
|
||
this.handleQuery();
|
||
},
|
||
handleSelectionChange(selection) {
|
||
this.ids = selection.map(item => item.id);
|
||
this.single = selection.length !== 1;
|
||
this.multiple = !selection.length;
|
||
},
|
||
handleAdd() {
|
||
this.reset();
|
||
this.open = true;
|
||
this.title = "添加订单";
|
||
},
|
||
handleUpdate(row) {
|
||
this.reset();
|
||
const id = row.id || this.ids;
|
||
getOrder(id).then(response => {
|
||
this.form = response.data;
|
||
this.form.progressiveMultifocal = this.form.progressiveMultifocal != null
|
||
? Number(this.form.progressiveMultifocal) : 0;
|
||
this.form.progressiveMultifocalPrice = this.form.progressiveMultifocalPrice != null
|
||
? Number(this.form.progressiveMultifocalPrice) : 0;
|
||
if (Number(this.form.progressiveMultifocal) !== 1) {
|
||
this.form.progressiveMultifocalPrice = 0;
|
||
}
|
||
if (!this.form.optometryList || this.form.optometryList.length === 0) {
|
||
this.form.optometryList = this.createDefaultOptometryList();
|
||
}
|
||
this.open = true;
|
||
this.title = "修改订单";
|
||
});
|
||
},
|
||
handleDetail(row) {
|
||
getOrder(row.id).then(response => {
|
||
this.detail = response.data || {};
|
||
this.detailPdMode = this.detectPdMode(this.detail.optometryList);
|
||
this.detailOpen = true;
|
||
});
|
||
},
|
||
canViewLogistics(row) {
|
||
if (!row || row.orderStatus == null) return false;
|
||
const status = String(row.orderStatus);
|
||
return status === this.ORDER_STATUS_SHIPPED
|
||
|| status === this.ORDER_STATUS_EXCHANGE_LOGISTICS
|
||
|| status === this.ORDER_STATUS_COMPLETED
|
||
|| status === this.ORDER_STATUS_EXCHANGE_COMPLETED;
|
||
},
|
||
canCompleteOrder(row) {
|
||
if (!row || row.orderStatus == null) return false;
|
||
const status = String(row.orderStatus);
|
||
return status === this.ORDER_STATUS_SHIPPED
|
||
|| status === this.ORDER_STATUS_EXCHANGE_LOGISTICS;
|
||
},
|
||
handleViewLogistics(row) {
|
||
if (!row || !row.id) return;
|
||
const noLogisticsTip = '未查到物流信息';
|
||
getOrderLogistics(row.id).then((body) => {
|
||
const data = body && body.data;
|
||
if (!data || !data.expressNo) {
|
||
this.$message.info(noLogisticsTip);
|
||
return;
|
||
}
|
||
const orderNo = data.orderNo || row.orderNo;
|
||
const expressCompany = data.expressCompany || '未知物流公司';
|
||
const expressNo = data.expressNo;
|
||
const mobile = data.receiverPhone || row.receiverPhone;
|
||
const base = process.env.VUE_APP_BASE_API || '';
|
||
return axios.get(`${base}/tool/express/query`, {
|
||
params: { expressNo, mobile: mobile || undefined },
|
||
headers: {
|
||
Authorization: getToken() ? 'Bearer ' + getToken() : ''
|
||
},
|
||
timeout: 15000
|
||
}).then((res) => {
|
||
const pkg = res.data;
|
||
this.logisticsBasic = { orderNo, expressCompany, expressNo };
|
||
if (!pkg || Number(pkg.code) !== 200) {
|
||
this.logisticsDetail = null;
|
||
this.logisticsDialogVisible = true;
|
||
return;
|
||
}
|
||
const detailRaw = pkg.data && pkg.data.data ? pkg.data.data : pkg.data;
|
||
if (!detailRaw) {
|
||
this.logisticsDetail = null;
|
||
this.logisticsDialogVisible = true;
|
||
return;
|
||
}
|
||
const traceRawList = detailRaw.logisticsTraceDetailList;
|
||
const traceList = Array.isArray(traceRawList) ? traceRawList.slice() : [];
|
||
traceList.sort((a, b) => (Number(b.time) || 0) - (Number(a.time) || 0));
|
||
const traces = traceList.map(item => ({
|
||
timeDesc: item.timeDesc || '',
|
||
line: [item.timeDesc, item.desc].filter(Boolean).join(' ')
|
||
})).filter(t => t.line);
|
||
this.logisticsDetail = traces.length > 0 ? { traces } : null;
|
||
this.logisticsDialogVisible = true;
|
||
}).catch(() => {
|
||
this.logisticsBasic = { orderNo, expressCompany, expressNo };
|
||
this.logisticsDetail = null;
|
||
this.logisticsDialogVisible = true;
|
||
});
|
||
}).catch(() => {
|
||
this.$message.info(noLogisticsTip);
|
||
});
|
||
},
|
||
handleStatusSelectVisible(row, visible) {
|
||
if (visible) {
|
||
row._prevOrderStatus = row.orderStatus;
|
||
}
|
||
},
|
||
handleOrderStatusChange(row) {
|
||
if (!row || !row.id) {
|
||
return;
|
||
}
|
||
if (row.orderStatus === row._prevOrderStatus) {
|
||
return;
|
||
}
|
||
const label = this.selectDictLabel(this.dict.type.jy_order_status, row.orderStatus);
|
||
this.$modal.confirm(`确认将订单"${row.orderNo}"状态变更为"${label}"吗?`).then(() => {
|
||
return changeOrderStatus({
|
||
orderId: row.id,
|
||
orderStatus: row.orderStatus
|
||
});
|
||
}).then(() => {
|
||
row._prevOrderStatus = row.orderStatus;
|
||
this.$modal.msgSuccess('状态更新成功');
|
||
}).catch(() => {
|
||
row.orderStatus = row._prevOrderStatus;
|
||
});
|
||
},
|
||
handleReject(row) {
|
||
if (!row || !row.id) {
|
||
return;
|
||
}
|
||
this.rejectForm = {
|
||
orderId: row.id,
|
||
orderNo: row.orderNo,
|
||
reason: ''
|
||
};
|
||
this.rejectOpen = true;
|
||
this.$nextTick(() => {
|
||
if (this.$refs.rejectForm) {
|
||
this.$refs.rejectForm.clearValidate();
|
||
}
|
||
});
|
||
},
|
||
submitReject() {
|
||
this.$refs.rejectForm.validate(valid => {
|
||
if (!valid) {
|
||
return;
|
||
}
|
||
this.rejectLoading = true;
|
||
rejectOrder({
|
||
orderId: this.rejectForm.orderId,
|
||
reason: this.rejectForm.reason
|
||
}).then(() => {
|
||
this.$modal.msgSuccess('驳回成功');
|
||
this.rejectOpen = false;
|
||
this.getList();
|
||
}).finally(() => {
|
||
this.rejectLoading = false;
|
||
});
|
||
});
|
||
},
|
||
handleClose(row) {
|
||
if (!row || !row.id) {
|
||
return;
|
||
}
|
||
this.$modal.confirm(`确认关闭订单"${row.orderNo}"吗?`).then(() => {
|
||
return closeOrder({ orderId: row.id });
|
||
}).then(() => {
|
||
this.$modal.msgSuccess('关闭成功');
|
||
this.getList();
|
||
}).catch(() => {});
|
||
},
|
||
handleComplete(row) {
|
||
if (!row || !row.id) {
|
||
return;
|
||
}
|
||
this.$modal.confirm(`确认完成订单"${row.orderNo}"吗?`).then(() => {
|
||
return completeOrder({ orderId: row.id });
|
||
}).then(() => {
|
||
this.$modal.msgSuccess('操作成功');
|
||
this.getList();
|
||
}).catch(() => {});
|
||
},
|
||
handleAgreeExchange(row) {
|
||
if (!row || !row.id) {
|
||
return;
|
||
}
|
||
this.$modal.confirm(`确认同意订单"${row.orderNo}"的换货申请吗?`).then(() => {
|
||
return agreeExchangeOrder({ orderId: row.id });
|
||
}).then(() => {
|
||
this.$modal.msgSuccess('已同意换货申请');
|
||
this.getList();
|
||
}).catch(() => {});
|
||
},
|
||
handleRejectExchange(row) {
|
||
if (!row || !row.id) {
|
||
return;
|
||
}
|
||
this.exchangeRejectForm = {
|
||
orderId: row.id,
|
||
orderNo: row.orderNo,
|
||
reason: ''
|
||
};
|
||
this.exchangeRejectOpen = true;
|
||
this.$nextTick(() => {
|
||
if (this.$refs.exchangeRejectForm) {
|
||
this.$refs.exchangeRejectForm.clearValidate();
|
||
}
|
||
});
|
||
},
|
||
submitExchangeReject() {
|
||
this.$refs.exchangeRejectForm.validate(valid => {
|
||
if (!valid) {
|
||
return;
|
||
}
|
||
this.exchangeRejectLoading = true;
|
||
rejectExchangeOrder({
|
||
orderId: this.exchangeRejectForm.orderId,
|
||
reason: this.exchangeRejectForm.reason
|
||
}).then(() => {
|
||
this.$modal.msgSuccess('已拒绝换货申请');
|
||
this.exchangeRejectOpen = false;
|
||
this.getList();
|
||
}).finally(() => {
|
||
this.exchangeRejectLoading = false;
|
||
});
|
||
});
|
||
},
|
||
loadAssignLensFactoryList(lensId, token) {
|
||
if (!lensId) {
|
||
this.assignLensFactoryList = [];
|
||
return;
|
||
}
|
||
listLensFactoryTenant(lensId).then(response => {
|
||
if (token !== this.assignDialogToken) {
|
||
return;
|
||
}
|
||
this.assignLensFactoryList = response.data || [];
|
||
});
|
||
},
|
||
resetAssignDialog() {
|
||
this.assignDialogToken += 1;
|
||
this.assignPreview = {};
|
||
this.assignLensFactoryList = [];
|
||
this.assignLoading = false;
|
||
this.assignForm = {
|
||
orderId: null,
|
||
orderNo: null,
|
||
lensId: null,
|
||
lensText: '',
|
||
progressiveMultifocal: 0,
|
||
lensFactoryTenantId: null
|
||
};
|
||
},
|
||
handleAssign(row) {
|
||
this.assignDialogToken += 1;
|
||
const token = this.assignDialogToken;
|
||
this.assignDialogKey += 1;
|
||
this.assignPreview = {};
|
||
this.assignLensFactoryList = [];
|
||
this.assignForm = {
|
||
orderId: row.id,
|
||
orderNo: row.orderNo,
|
||
lensId: row.lensId,
|
||
lensText: this.formatLens(row),
|
||
progressiveMultifocal: row.progressiveMultifocal,
|
||
lensFactoryTenantId: null
|
||
};
|
||
this.assignOpen = true;
|
||
this.loadAssignLensFactoryList(row.lensId, token);
|
||
this.$nextTick(() => {
|
||
if (this.$refs.assignForm) {
|
||
this.resetForm('assignForm');
|
||
}
|
||
});
|
||
},
|
||
handleAssignFactoryChange(lensFactoryTenantId) {
|
||
if (!lensFactoryTenantId) {
|
||
this.assignPreview = {};
|
||
return;
|
||
}
|
||
const token = this.assignDialogToken;
|
||
const orderId = this.assignForm.orderId;
|
||
previewAssignPrice(orderId, lensFactoryTenantId).then(response => {
|
||
if (token !== this.assignDialogToken || this.assignForm.orderId !== orderId) {
|
||
return;
|
||
}
|
||
this.assignPreview = response.data || {};
|
||
}).catch(() => {
|
||
if (token !== this.assignDialogToken || this.assignForm.orderId !== orderId) {
|
||
return;
|
||
}
|
||
this.assignPreview = {};
|
||
});
|
||
},
|
||
submitAssign() {
|
||
this.$refs.assignForm.validate(valid => {
|
||
if (!valid) {
|
||
return;
|
||
}
|
||
this.assignLoading = true;
|
||
assignOrder({
|
||
orderId: this.assignForm.orderId,
|
||
lensFactoryTenantId: this.assignForm.lensFactoryTenantId
|
||
}).then(() => {
|
||
this.$modal.msgSuccess('分配成功');
|
||
this.assignOpen = false;
|
||
this.getList();
|
||
}).finally(() => {
|
||
this.assignLoading = false;
|
||
});
|
||
});
|
||
},
|
||
submitForm() {
|
||
this.$refs["form"].validate(valid => {
|
||
if (valid) {
|
||
const payload = {
|
||
...this.form,
|
||
progressiveMultifocal: this.form.progressiveMultifocal != null
|
||
? Number(this.form.progressiveMultifocal) : 0,
|
||
progressiveMultifocalPrice: Number(this.form.progressiveMultifocal) === 1
|
||
? this.resolveProgressiveMultifocalPrice()
|
||
: 0
|
||
};
|
||
if (Number(payload.progressiveMultifocal) !== 1 && payload.optometryList) {
|
||
payload.optometryList.forEach(row => {
|
||
row.nearAdd = null;
|
||
row.pupilHeight = null;
|
||
});
|
||
}
|
||
if (payload.optometryList) {
|
||
payload.optometryList.forEach(row => {
|
||
if (!this.isAxisAEditable(row)) {
|
||
row.axisA = null;
|
||
}
|
||
});
|
||
}
|
||
if (Number(payload.progressiveMultifocal) === 1) {
|
||
if (!payload.lensFactoryTenantId) {
|
||
this.$modal.msgWarning("选择渐进多焦点时需先选择镜片厂");
|
||
return;
|
||
}
|
||
if (!payload.progressiveMultifocalPrice || Number(payload.progressiveMultifocalPrice) <= 0) {
|
||
this.$modal.msgWarning("所选镜片厂未配置渐进多焦点价格");
|
||
return;
|
||
}
|
||
}
|
||
if (this.form.id != null) {
|
||
updateOrder(payload).then(() => {
|
||
this.$modal.msgSuccess("修改成功");
|
||
this.open = false;
|
||
this.getList();
|
||
});
|
||
} else {
|
||
addOrder(payload).then(() => {
|
||
this.$modal.msgSuccess("新增成功");
|
||
this.open = false;
|
||
this.getList();
|
||
});
|
||
}
|
||
}
|
||
});
|
||
},
|
||
handleDelete(row) {
|
||
const ids = row.id || this.ids;
|
||
this.$modal.confirm('是否确认删除订单编号为"' + ids + '"的数据项?').then(function() {
|
||
return delOrder(ids);
|
||
}).then(() => {
|
||
this.getList();
|
||
this.$modal.msgSuccess("删除成功");
|
||
}).catch(() => {});
|
||
},
|
||
handleGenerateSettlement() {
|
||
this.settlementGenerateForm = { settleYearMonth: undefined };
|
||
this.settlementGenerateOpen = true;
|
||
this.$nextTick(() => {
|
||
if (this.$refs.settlementGenerateForm) {
|
||
this.$refs.settlementGenerateForm.clearValidate();
|
||
}
|
||
});
|
||
},
|
||
submitGenerateSettlement() {
|
||
this.$refs.settlementGenerateForm.validate(valid => {
|
||
if (!valid) return;
|
||
const yearMonth = this.settlementGenerateForm.settleYearMonth;
|
||
this.settlementGenerateLoading = true;
|
||
checkFeeSettlement(yearMonth).then(res => {
|
||
const check = res.data || {};
|
||
if (check.exists) {
|
||
const nos = (check.settlementNos || []).join('、');
|
||
return this.$modal.confirm(
|
||
`该年月已存在 ${check.count} 张费用结算单${nos ? '(' + nos + ')' : ''},是否删除后重新生成?`
|
||
).then(() => {
|
||
return generateFeeSettlement({ settleYearMonth: yearMonth, forceRegenerate: true });
|
||
});
|
||
}
|
||
return generateFeeSettlement({ settleYearMonth: yearMonth, forceRegenerate: false });
|
||
}).then(res => {
|
||
if (res) {
|
||
this.$modal.msgSuccess(res.msg || '生成成功');
|
||
this.settlementGenerateOpen = false;
|
||
}
|
||
}).catch(() => {}).finally(() => {
|
||
this.settlementGenerateLoading = false;
|
||
});
|
||
});
|
||
},
|
||
handleExport() {
|
||
this.download('jysystem/order/export', {
|
||
...this.queryParams
|
||
}, `order_${new Date().getTime()}.xlsx`);
|
||
},
|
||
handleBatchExportExcel() {
|
||
if (!this.ids.length) {
|
||
this.$modal.msgWarning('请先选择要导出的订单');
|
||
return;
|
||
}
|
||
this.download('jysystem/order/export/batch/' + this.ids.join(','), {}, `order_batch_${new Date().getTime()}.xlsx`);
|
||
},
|
||
handleBatchExportPdf() {
|
||
if (!this.ids.length) {
|
||
this.$modal.msgWarning('请先选择要导出的订单');
|
||
return;
|
||
}
|
||
this.download('jysystem/order/exportPdf/batch/' + this.ids.join(','), {}, `order_batch_${new Date().getTime()}.pdf`);
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.degree-sup {
|
||
font-size: 10px;
|
||
line-height: 1;
|
||
vertical-align: super;
|
||
}
|
||
|
||
.price-total-value {
|
||
font-weight: 700;
|
||
font-size: 16px;
|
||
color: #f56c6c;
|
||
}
|
||
</style>
|
||
|
||
<style lang="scss">
|
||
.lens-order-form-dialog,
|
||
.lens-order-detail-dialog {
|
||
border-radius: 16px;
|
||
overflow: hidden;
|
||
box-shadow: 0 24px 48px rgba(37, 99, 235, 0.12), 0 8px 24px rgba(15, 23, 42, 0.08);
|
||
|
||
.el-dialog__header {
|
||
padding: 20px 28px 18px;
|
||
background: linear-gradient(135deg, rgba(37, 99, 235, 0.08) 0%, rgba(147, 51, 234, 0.06) 100%);
|
||
border-bottom: 1px solid rgba(37, 99, 235, 0.12);
|
||
}
|
||
|
||
.el-dialog__headerbtn {
|
||
top: 22px;
|
||
right: 24px;
|
||
|
||
.el-dialog__close {
|
||
color: #64748b;
|
||
font-size: 18px;
|
||
|
||
&:hover {
|
||
color: #2563eb;
|
||
}
|
||
}
|
||
}
|
||
|
||
.el-dialog__body {
|
||
padding: 20px 28px 8px;
|
||
background: linear-gradient(180deg, #f8fafc 0%, #f1f5f9 100%);
|
||
overflow: visible;
|
||
}
|
||
|
||
.el-dialog__footer {
|
||
padding: 16px 28px 22px;
|
||
background: #fff;
|
||
border-top: 1px solid rgba(37, 99, 235, 0.08);
|
||
}
|
||
}
|
||
|
||
.lens-dialog-header {
|
||
.lens-dialog-title {
|
||
margin: 0 0 6px;
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
background: linear-gradient(90deg, #2563eb 0%, #7c3aed 100%);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
color: transparent;
|
||
}
|
||
|
||
.lens-dialog-subtitle {
|
||
margin: 0;
|
||
font-size: 13px;
|
||
color: #64748b;
|
||
letter-spacing: 0.02em;
|
||
}
|
||
}
|
||
|
||
.lens-order-form,
|
||
.lens-order-detail {
|
||
.lens-form-section {
|
||
margin-bottom: 18px;
|
||
padding: 18px 20px 8px;
|
||
background: #fff;
|
||
border: 1px solid rgba(37, 99, 235, 0.1);
|
||
border-radius: 12px;
|
||
box-shadow: 0 4px 16px rgba(15, 23, 42, 0.04);
|
||
position: relative;
|
||
overflow: hidden;
|
||
|
||
&::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 3px;
|
||
background: linear-gradient(90deg, #2563eb 0%, #9333ea 100%);
|
||
opacity: 0.85;
|
||
}
|
||
|
||
&--optometry {
|
||
padding-bottom: 16px;
|
||
}
|
||
}
|
||
|
||
.section-head {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 14px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.section-index {
|
||
flex-shrink: 0;
|
||
width: 36px;
|
||
height: 36px;
|
||
line-height: 36px;
|
||
text-align: center;
|
||
font-size: 13px;
|
||
font-weight: 700;
|
||
color: #2563eb;
|
||
background: linear-gradient(135deg, rgba(37, 99, 235, 0.12) 0%, rgba(147, 51, 234, 0.1) 100%);
|
||
border: 1px solid rgba(37, 99, 235, 0.15);
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.section-text {
|
||
h4 {
|
||
margin: 0 0 4px;
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
color: #1e293b;
|
||
}
|
||
|
||
p {
|
||
margin: 0;
|
||
font-size: 12px;
|
||
color: #94a3b8;
|
||
}
|
||
}
|
||
|
||
.section-body {
|
||
padding-left: 2px;
|
||
}
|
||
|
||
.lens-optometry-table {
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
border: 1px solid rgba(37, 99, 235, 0.12);
|
||
|
||
&::before {
|
||
display: none;
|
||
}
|
||
|
||
th {
|
||
background: linear-gradient(90deg, #eff6ff 0%, #f5f3ff 100%) !important;
|
||
color: #334155 !important;
|
||
font-weight: 600;
|
||
border-color: rgba(37, 99, 235, 0.1) !important;
|
||
}
|
||
|
||
td {
|
||
border-color: rgba(148, 163, 184, 0.2) !important;
|
||
background: #fff;
|
||
}
|
||
|
||
tr:hover > td {
|
||
background: rgba(239, 246, 255, 0.5) !important;
|
||
}
|
||
}
|
||
|
||
.el-input__inner,
|
||
.el-textarea__inner {
|
||
border-radius: 8px;
|
||
border-color: rgba(37, 99, 235, 0.15);
|
||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||
|
||
&:focus {
|
||
border-color: #2563eb;
|
||
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
|
||
}
|
||
}
|
||
|
||
.el-form-item__label {
|
||
color: #475569;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
.lens-order-detail {
|
||
.detail-descriptions {
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
|
||
.el-descriptions__table {
|
||
table-layout: fixed;
|
||
width: 100%;
|
||
}
|
||
|
||
.el-descriptions-item__label {
|
||
width: 116px;
|
||
min-width: 116px;
|
||
background: linear-gradient(90deg, #eff6ff 0%, #f5f3ff 100%) !important;
|
||
color: #475569 !important;
|
||
font-weight: 600;
|
||
border-color: rgba(37, 99, 235, 0.1) !important;
|
||
}
|
||
|
||
.el-descriptions-item__content {
|
||
color: #1e293b;
|
||
border-color: rgba(37, 99, 235, 0.1) !important;
|
||
}
|
||
}
|
||
|
||
.detail-descriptions--price {
|
||
.el-descriptions-item__content {
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
}
|
||
|
||
.detail-attachment-link {
|
||
margin-right: 12px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.price-total-value {
|
||
font-weight: 700;
|
||
font-size: 16px;
|
||
color: #ef4444;
|
||
}
|
||
|
||
.lens-detail-table {
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
border: 1px solid rgba(37, 99, 235, 0.12);
|
||
|
||
&::before {
|
||
display: none;
|
||
}
|
||
|
||
th {
|
||
background: linear-gradient(90deg, #eff6ff 0%, #f5f3ff 100%) !important;
|
||
color: #334155 !important;
|
||
font-weight: 600;
|
||
border-color: rgba(37, 99, 235, 0.1) !important;
|
||
}
|
||
|
||
td {
|
||
border-color: rgba(148, 163, 184, 0.2) !important;
|
||
background: #fff;
|
||
color: #334155;
|
||
}
|
||
|
||
tr:hover > td {
|
||
background: rgba(239, 246, 255, 0.5) !important;
|
||
}
|
||
}
|
||
|
||
.detail-logistics-fee-block {
|
||
margin-top: 12px;
|
||
}
|
||
|
||
.detail-empty-tip {
|
||
margin-top: 10px;
|
||
padding: 14px;
|
||
text-align: center;
|
||
font-size: 13px;
|
||
color: #94a3b8;
|
||
background: linear-gradient(90deg, rgba(239, 246, 255, 0.6) 0%, rgba(245, 243, 255, 0.6) 100%);
|
||
border: 1px dashed rgba(37, 99, 235, 0.15);
|
||
border-radius: 10px;
|
||
}
|
||
}
|
||
|
||
.logistics-traces {
|
||
max-height: 360px;
|
||
overflow-y: auto;
|
||
padding: 4px 8px 0;
|
||
}
|
||
|
||
.lens-dialog-footer {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 10px;
|
||
|
||
.lens-btn-ghost {
|
||
border-color: #cbd5e1;
|
||
color: #64748b;
|
||
border-radius: 8px;
|
||
padding: 10px 20px;
|
||
|
||
&:hover {
|
||
color: #2563eb;
|
||
border-color: #93c5fd;
|
||
background: #f8fafc;
|
||
}
|
||
}
|
||
|
||
.lens-btn-primary {
|
||
border: none;
|
||
color: #fff;
|
||
background: linear-gradient(135deg, #2563eb 0%, #7c3aed 100%);
|
||
border-radius: 8px;
|
||
padding: 10px 24px;
|
||
box-shadow: 0 6px 16px rgba(37, 99, 235, 0.28);
|
||
|
||
&:hover {
|
||
background: linear-gradient(135deg, #1d4ed8 0%, #6d28d9 100%);
|
||
box-shadow: 0 8px 20px rgba(37, 99, 235, 0.35);
|
||
}
|
||
}
|
||
}
|
||
</style>
|