chore: prepare release build
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { adminApi, type AdminOrderDetail, type AdminOrderListItem, type AdminOrderWarehouseOption } from "../../api/admin";
|
||||
import { adminApi, type AdminFileAsset, type AdminManualOrderCreatePayload, type AdminManualOrderMeta, type AdminOrderDetail, type AdminOrderListItem, type AdminOrderWarehouseOption } from "../../api/admin";
|
||||
import OrderStatusTag from "../../components/OrderStatusTag.vue";
|
||||
|
||||
const loading = ref(false);
|
||||
@@ -18,6 +18,12 @@ const returnDialogVisible = ref(false);
|
||||
const returnSubmitting = ref(false);
|
||||
const returnExpressCompany = ref("");
|
||||
const returnTrackingNo = ref("");
|
||||
const manualDialogVisible = ref(false);
|
||||
const manualSubmitting = ref(false);
|
||||
const manualMetaLoading = ref(false);
|
||||
const manualUploading = ref(false);
|
||||
const manualMeta = ref<AdminManualOrderMeta>({ categories: [], brands: [] });
|
||||
const manualForm = ref<AdminManualOrderCreatePayload>(createManualOrderForm());
|
||||
|
||||
const keyword = ref("");
|
||||
const serviceProvider = ref("");
|
||||
@@ -48,6 +54,7 @@ const sourceChannelOptions = [
|
||||
{ label: "小程序", value: "mini_program" },
|
||||
{ label: "H5", value: "h5" },
|
||||
{ label: "大客户推送订单", value: "enterprise_push" },
|
||||
{ label: "后台补录订单", value: "manual_entry" },
|
||||
];
|
||||
|
||||
const usageStatusMap: Record<string, string> = {
|
||||
@@ -107,6 +114,52 @@ const logisticsActionText = computed(() => {
|
||||
const canSubmitReturnLogistics = computed(() => Boolean(detail.value?.order_info.can_submit_return_logistics));
|
||||
const returnLogisticsBlockReason = computed(() => detail.value?.order_info.return_logistics_block_reason || "");
|
||||
const canMarkReturnReceived = computed(() => Boolean(detail.value?.order_info.can_mark_return_received));
|
||||
const manualBrandOptions = computed(() => {
|
||||
const categoryId = manualForm.value.product_info.category_id;
|
||||
const provider = manualForm.value.service_provider;
|
||||
return manualMeta.value.brands.filter((item) => {
|
||||
const categoryMatched = !categoryId || !item.category_ids.length || item.category_ids.includes(categoryId);
|
||||
const providerMatched = !item.supported_service_types.length || item.supported_service_types.includes(provider);
|
||||
return categoryMatched && providerMatched;
|
||||
});
|
||||
});
|
||||
|
||||
function createManualOrderForm(): AdminManualOrderCreatePayload {
|
||||
return {
|
||||
service_provider: "anxinyan",
|
||||
product_info: {
|
||||
category_id: 0,
|
||||
brand_id: 0,
|
||||
product_name: "",
|
||||
color: "",
|
||||
size_spec: "",
|
||||
serial_no: "",
|
||||
},
|
||||
extra_info: {
|
||||
purchase_channel: "",
|
||||
purchase_price: 0,
|
||||
usage_status: "",
|
||||
condition_desc: "",
|
||||
remark: "",
|
||||
},
|
||||
return_address: {
|
||||
consignee: "",
|
||||
mobile: "",
|
||||
province: "",
|
||||
city: "",
|
||||
district: "",
|
||||
detail_address: "",
|
||||
},
|
||||
materials: [
|
||||
{
|
||||
item_code: "manual_initial",
|
||||
item_name: "补录资料",
|
||||
is_required: false,
|
||||
files: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
async function fetchOrders() {
|
||||
loading.value = true;
|
||||
@@ -126,6 +179,82 @@ async function fetchOrders() {
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureManualMeta() {
|
||||
if (manualMeta.value.categories.length && manualMeta.value.brands.length) return;
|
||||
manualMetaLoading.value = true;
|
||||
try {
|
||||
const response = await adminApi.getManualOrderMeta();
|
||||
manualMeta.value = response.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
ElMessage.error("补录订单选项加载失败");
|
||||
} finally {
|
||||
manualMetaLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function openManualDialog() {
|
||||
manualForm.value = createManualOrderForm();
|
||||
manualDialogVisible.value = true;
|
||||
await ensureManualMeta();
|
||||
}
|
||||
|
||||
function handleManualCategoryChange() {
|
||||
const selectedBrand = manualBrandOptions.value.find((item) => item.id === manualForm.value.product_info.brand_id);
|
||||
if (!selectedBrand) {
|
||||
manualForm.value.product_info.brand_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function validateManualForm() {
|
||||
const form = manualForm.value;
|
||||
if (!form.product_info.category_id || !form.product_info.brand_id || !form.product_info.product_name.trim()) {
|
||||
ElMessage.warning("请完整填写品类、品牌和商品名称");
|
||||
return false;
|
||||
}
|
||||
const address = form.return_address;
|
||||
if (!address.consignee.trim() || !address.mobile.trim() || !address.province.trim() || !address.city.trim() || !address.district.trim() || !address.detail_address.trim()) {
|
||||
ElMessage.warning("请完整填写寄回收件信息");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async function uploadManualMaterial(options: { file: File }) {
|
||||
manualUploading.value = true;
|
||||
try {
|
||||
const response = await adminApi.uploadManualOrderFile(options.file);
|
||||
manualForm.value.materials[0].files.push(response.data);
|
||||
ElMessage.success("资料已上传");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
ElMessage.error(error instanceof Error ? error.message : "资料上传失败");
|
||||
} finally {
|
||||
manualUploading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function removeManualMaterial(file: AdminFileAsset) {
|
||||
manualForm.value.materials[0].files = manualForm.value.materials[0].files.filter((item) => item.file_url !== file.file_url);
|
||||
}
|
||||
|
||||
async function submitManualOrder() {
|
||||
if (!validateManualForm()) return;
|
||||
manualSubmitting.value = true;
|
||||
try {
|
||||
const payload: AdminManualOrderCreatePayload = JSON.parse(JSON.stringify(manualForm.value));
|
||||
const response = await adminApi.createManualOrder(payload);
|
||||
ElMessage.success(`补录订单已创建:${response.data.order_no} / ${response.data.appraisal_no}`);
|
||||
manualDialogVisible.value = false;
|
||||
await fetchOrders();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
ElMessage.error(error instanceof Error ? error.message : "补录订单创建失败");
|
||||
} finally {
|
||||
manualSubmitting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function openDetail(row: AdminOrderListItem) {
|
||||
detailLoading.value = true;
|
||||
drawerVisible.value = true;
|
||||
@@ -289,6 +418,7 @@ onMounted(fetchOrders);
|
||||
<el-option v-for="item in sourceChannelOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
<el-button type="primary" @click="fetchOrders">查询</el-button>
|
||||
<el-button @click="openManualDialog">补录订单</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
@@ -665,6 +795,124 @@ onMounted(fetchOrders);
|
||||
<el-button type="primary" :loading="returnSubmitting" :disabled="!canSubmitReturnLogistics" @click="submitReturnLogistics">确认登记</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="manualDialogVisible" title="补录订单" width="860px" destroy-on-close>
|
||||
<div v-loading="manualMetaLoading" class="manual-order-form">
|
||||
<el-alert
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="补录订单创建后为待入库状态"
|
||||
description="创建成功后,可在入库台使用订单号或鉴定单号匹配并绑定内部流转挂牌,不需要填写寄入快递单号。"
|
||||
/>
|
||||
|
||||
<div class="manual-section">
|
||||
<div class="manual-section__title">订单与商品</div>
|
||||
<el-form label-position="top">
|
||||
<div class="manual-grid">
|
||||
<el-form-item label="服务类型">
|
||||
<el-select v-model="manualForm.service_provider" style="width: 100%">
|
||||
<el-option label="实物鉴定" value="anxinyan" />
|
||||
<el-option label="中检鉴定" value="zhongjian" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="品类">
|
||||
<el-select v-model="manualForm.product_info.category_id" filterable style="width: 100%" @change="handleManualCategoryChange">
|
||||
<el-option v-for="item in manualMeta.categories" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="品牌">
|
||||
<el-select v-model="manualForm.product_info.brand_id" filterable style="width: 100%">
|
||||
<el-option v-for="item in manualBrandOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品名称">
|
||||
<el-input v-model="manualForm.product_info.product_name" placeholder="例如:Classic Flap 手袋" />
|
||||
</el-form-item>
|
||||
<el-form-item label="颜色">
|
||||
<el-input v-model="manualForm.product_info.color" placeholder="可选" />
|
||||
</el-form-item>
|
||||
<el-form-item label="规格 / 尺寸">
|
||||
<el-input v-model="manualForm.product_info.size_spec" placeholder="可选" />
|
||||
</el-form-item>
|
||||
<el-form-item label="序列号">
|
||||
<el-input v-model="manualForm.product_info.serial_no" placeholder="可选" />
|
||||
</el-form-item>
|
||||
<el-form-item label="购买渠道">
|
||||
<el-input v-model="manualForm.extra_info.purchase_channel" placeholder="可选" />
|
||||
</el-form-item>
|
||||
<el-form-item label="购买价格">
|
||||
<el-input-number v-model="manualForm.extra_info.purchase_price" :min="0" :precision="2" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="使用情况">
|
||||
<el-select v-model="manualForm.extra_info.usage_status" clearable style="width: 100%">
|
||||
<el-option label="全新未使用" value="new" />
|
||||
<el-option label="轻微使用痕迹" value="light_use" />
|
||||
<el-option label="长期使用" value="used" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label="成色说明">
|
||||
<el-input v-model="manualForm.extra_info.condition_desc" type="textarea" :rows="3" placeholder="可选" />
|
||||
</el-form-item>
|
||||
<el-form-item label="内部备注">
|
||||
<el-input v-model="manualForm.extra_info.remark" type="textarea" :rows="3" placeholder="可选" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="manual-section">
|
||||
<div class="manual-section__title">寄回信息</div>
|
||||
<el-form label-position="top">
|
||||
<div class="manual-grid">
|
||||
<el-form-item label="收件人">
|
||||
<el-input v-model="manualForm.return_address.consignee" placeholder="用于匹配或创建用户" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号">
|
||||
<el-input v-model="manualForm.return_address.mobile" placeholder="按手机号复用已有用户" />
|
||||
</el-form-item>
|
||||
<el-form-item label="省份">
|
||||
<el-input v-model="manualForm.return_address.province" placeholder="例如:广东省" />
|
||||
</el-form-item>
|
||||
<el-form-item label="城市">
|
||||
<el-input v-model="manualForm.return_address.city" placeholder="例如:深圳市" />
|
||||
</el-form-item>
|
||||
<el-form-item label="区县">
|
||||
<el-input v-model="manualForm.return_address.district" placeholder="例如:南山区" />
|
||||
</el-form-item>
|
||||
<el-form-item label="详细地址">
|
||||
<el-input v-model="manualForm.return_address.detail_address" placeholder="街道、门牌号" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="manual-section">
|
||||
<div class="manual-section__title">初始资料</div>
|
||||
<div class="manual-upload-head">
|
||||
<el-upload
|
||||
:show-file-list="false"
|
||||
:http-request="uploadManualMaterial"
|
||||
:disabled="manualUploading"
|
||||
multiple
|
||||
>
|
||||
<el-button :loading="manualUploading">上传图片/视频/PDF</el-button>
|
||||
</el-upload>
|
||||
<span class="manual-upload-hint">{{ manualForm.materials[0].files.length }} 个资料文件</span>
|
||||
</div>
|
||||
<div v-if="manualForm.materials[0].files.length" class="manual-file-list">
|
||||
<div v-for="file in manualForm.materials[0].files" :key="file.file_url" class="manual-file-item">
|
||||
<span>{{ file.name || file.file_url }}</span>
|
||||
<el-button link type="danger" @click="removeManualMaterial(file)">移除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="manualDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="manualSubmitting" :disabled="manualUploading || manualMetaLoading" @click="submitManualOrder">创建补录订单</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@@ -789,6 +1037,65 @@ onMounted(fetchOrders);
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.manual-order-form {
|
||||
display: grid;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.manual-section {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.manual-section__title {
|
||||
color: var(--admin-text-main);
|
||||
font-size: 16px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.manual-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0 18px;
|
||||
}
|
||||
|
||||
.manual-upload-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.manual-upload-hint {
|
||||
color: var(--admin-text-subtle);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.manual-file-list {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.manual-file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
min-width: 0;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--admin-border);
|
||||
border-radius: 8px;
|
||||
background: #fffdfa;
|
||||
}
|
||||
|
||||
.manual-file-item span {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: var(--admin-text-main);
|
||||
font-size: 13px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media (max-width: 1280px) {
|
||||
.order-detail-hero {
|
||||
grid-template-columns: 1fr;
|
||||
@@ -810,5 +1117,9 @@ onMounted(fetchOrders);
|
||||
.order-detail-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.manual-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user