Simplify manual order creation

This commit is contained in:
wushumin
2026-05-21 18:55:01 +08:00
parent d0c4332468
commit b98d6164a7
5 changed files with 49 additions and 233 deletions

View File

@@ -263,6 +263,7 @@ export interface AdminManualOrderCreatePayload {
product_info: {
category_id: number;
brand_id: number;
brand_name: string;
product_name: string;
color: string;
size_spec: string;

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { adminApi, type AdminFileAsset, type AdminManualOrderCreatePayload, type AdminManualOrderMeta, type AdminOrderDetail, type AdminOrderListItem, type AdminOrderWarehouseOption } from "../../api/admin";
import { adminApi, type AdminManualOrderCreatePayload, type AdminManualOrderMeta, type AdminOrderDetail, type AdminOrderListItem, type AdminOrderWarehouseOption } from "../../api/admin";
import OrderStatusTag from "../../components/OrderStatusTag.vue";
const loading = ref(false);
@@ -21,7 +21,6 @@ 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());
@@ -114,22 +113,13 @@ 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,
brand_name: "",
product_name: "",
color: "",
size_spec: "",
@@ -180,7 +170,7 @@ async function fetchOrders() {
}
async function ensureManualMeta() {
if (manualMeta.value.categories.length && manualMeta.value.brands.length) return;
if (manualMeta.value.categories.length) return;
manualMetaLoading.value = true;
try {
const response = await adminApi.getManualOrderMeta();
@@ -199,17 +189,10 @@ async function openManualDialog() {
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) {
ElMessage.warning("请完整填写品类和品牌");
if (!form.product_info.category_id) {
ElMessage.warning("请选择品类");
return false;
}
const address = form.return_address;
@@ -220,29 +203,13 @@ function validateManualForm() {
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));
payload.product_info.brand_id = 0;
payload.product_info.brand_name = payload.product_info.brand_name.trim();
const response = await adminApi.createManualOrder(payload);
ElMessage.success(`补录订单已创建:${response.data.order_no} / ${response.data.appraisal_no}`);
manualDialogVisible.value = false;
@@ -817,14 +784,12 @@ onMounted(fetchOrders);
</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-select v-model="manualForm.product_info.category_id" filterable style="width: 100%">
<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 label="品牌(选填)">
<el-input v-model="manualForm.product_info.brand_name" maxlength="128" placeholder="请输入品牌名称,可不填" />
</el-form-item>
<el-form-item label="商品名称">
<el-input v-model="manualForm.product_info.product_name" placeholder="可选例如Classic Flap 手袋" />
@@ -838,26 +803,7 @@ onMounted(fetchOrders);
<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>
@@ -887,30 +833,10 @@ onMounted(fetchOrders);
</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>
<el-button type="primary" :loading="manualSubmitting" :disabled="manualMetaLoading" @click="submitManualOrder">创建补录订单</el-button>
</template>
</el-dialog>
</template>