This commit is contained in:
2026-04-14 12:14:45 +08:00
parent 4c16617e6c
commit 126e15dfa9
11 changed files with 684 additions and 14 deletions
@@ -288,8 +288,8 @@ onMounted(fetchOrder);
<template>
<div class="mx-auto max-w-6xl px-6 py-6">
<!-- 返回按钮 -->
<div class="mb-4">
<!-- 顶部操作栏返回 + 编辑 -->
<div class="mb-4 flex items-center justify-between">
<RouterLink
to="/purchase"
class="inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-dk-card dark:hover:text-gray-200"
@@ -297,6 +297,17 @@ onMounted(fetchOrder);
<IconChevronLeft :size="16" />
{{ t("purchase.back_to_list") }}
</RouterLink>
<!-- 编辑按钮 -->
<RouterLink
v-if="order"
:to="`/purchase/editorder/${order.ID}`"
class="inline-flex items-center gap-1.5 rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 dark:border-dk-muted dark:bg-dk-card dark:text-gray-300 dark:hover:bg-dk-base"
>
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
{{ t("purchase.edit_order") }}
</RouterLink>
</div>
<!-- Loading -->
@@ -538,7 +549,7 @@ onMounted(fetchOrder);
<td
class="px-6 py-3 text-base font-bold text-gray-900 dark:text-white"
>
{{ costTotalYuan.toFixed(2) }}
<!-- {{ costTotalYuan.toFixed(2) }} -->
</td>
<td class="px-6 py-3">
<span
@@ -113,10 +113,10 @@ const costEntries = reactive([]);
* 用户填写完表单后点击"添加"按钮加入 costEntries
*/
const newCost = reactive({
type: 1, // 费用类型:默认"单价"
type: "1", // 费用类型:默认"单价"
int: 1, // 数量:默认1
cost: 0, // 单价:默认0
currencyType: 1, // 货币类型:默认人民币
currencyType: "1", // 货币类型:默认人民币
});
// 费用验证错误状态:点击添加按钮后发现费用为0时触发
@@ -166,10 +166,10 @@ function addCostEntry() {
currencytype: newCost.currencyType,
});
// 添加后重置表单,以便继续添加下一条
newCost.type = 1;
newCost.type = "1";
newCost.int = 1;
newCost.cost = 0;
newCost.currencyType = 1;
newCost.currencyType = "1";
}
/**
@@ -230,6 +230,10 @@ async function handleSubmit() {
...h,
cost: Math.round(h.cost * 100),
costt: Math.round(h.costt * 100),
//转换type的类型,string转int
type:parseInt(h.type),
currencytype:parseInt(h.currencytype),
}));
// 开始 loading
@@ -0,0 +1,195 @@
<script setup>
/**
* 采购订单编辑页面
*
* 功能概述:
* - 通过路由参数 :id 加载已有订单数据
* - 使用 PurchaseOrderForm 组件展示可编辑表单
* - 提交时调用 /purchase/updateorder 保存修改
*/
import { reactive, ref, onMounted } from "vue";
import { useI18n } from "vue-i18n";
import { useRoute, useRouter } from "vue-router";
import { useToastStore } from "@/stores/toast";
import { usePageTitle } from "@/composables/usePageTitle";
import { useValidation } from "@/composables";
import { purchaseApi } from "@/api/purchase";
import PurchaseOrderForm from "@/components/PurchaseOrderForm.vue";
usePageTitle("purchase_addorder.edit_order");
const route = useRoute();
const router = useRouter();
const { t } = useI18n();
const toast = useToastStore();
const { validate, errors, clearErrors } = useValidation();
const orderId = Number(route.params.id);
// ==================== 状态 ====================
const loading = ref(false);
const pageLoading = ref(true);
const pageError = ref("");
/** 回填的费用明细(分为单位,传给 PurchaseOrderForm */
const initialCosts = ref([]);
/** 回填的图片列表 */
const initialPhotos = ref([]);
/** 表单数据 */
const form = reactive({
title: "",
remark: "",
link: "",
styles: "",
photos: [],
costs: [],
_costs: [], // 由 PurchaseOrderForm 组件同步的分为单位费用数组
});
/** PurchaseOrderForm 组件引用(用于获取图片哈希) */
const formRef = ref(null);
// ==================== 加载订单数据 ====================
onMounted(async () => {
if (!orderId) {
pageError.value = t("purchase.order_not_found");
pageLoading.value = false;
return;
}
try {
const res = await purchaseApi.getOrder(orderId);
console.log(res)
if (res.errCode !== 0 || res.raw?.err_code !== 0) {
pageError.value = t("purchase.order_not_found");
pageLoading.value = false;
return;
}
const { order, costs, photos } = res.raw.data;
// 回填基本信息
form.title = order.Title ?? "";
form.remark = order.Remark ?? "";
form.link = order.Link ?? "";
form.styles = order.Styles ?? "";
// 回填费用(传给子组件,由子组件转换为元展示)
initialCosts.value = costs ?? [];
// 回填图片
initialPhotos.value = photos ?? [];
} catch {
pageError.value = t("purchase.order_not_found");
} finally {
pageLoading.value = false;
}
});
// ==================== 提交 ====================
async function handleSubmit() {
clearErrors();
const ok = validate("title", form.title, t("purchase_addorder.title"));
if (!ok) return;
// 获取图片哈希
form.photos = formRef.value?.getPhotoHashes() ?? [];
// 使用子组件同步的费用(分为单位)
form.costs = form._costs ?? [];
loading.value = true;
try {
const res = await purchaseApi.updateOrder(orderId, {
title: form.title,
remark: form.remark,
link: form.link,
styles: form.styles,
photos: form.photos,
costs: form.costs,
});
if (res.errCode === 0 && res.raw?.err_code === 0) {
toast.success(t("message.save_ok"));
setTimeout(() => {
router.replace(`/purchase/showorder/${orderId}`);
}, 800);
} else {
toast.error(t("message.server_error"));
}
} catch {
toast.error(t("message.server_error"));
} finally {
loading.value = false;
}
}
</script>
<template>
<div class="mx-auto max-w-6xl px-6 py-6">
<!-- 加载中 -->
<div v-if="pageLoading" class="flex items-center justify-center py-20 text-gray-400">
<svg class="mr-2 h-5 w-5 animate-spin" viewBox="0 0 24 24" fill="none">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg>
{{ t("message.loading") }}
</div>
<!-- 订单不存在 -->
<div v-else-if="pageError" class="rounded-xl border border-red-200 bg-red-50 px-6 py-10 text-center text-red-500 dark:border-red-800 dark:bg-red-900/20">
{{ pageError }}
</div>
<!-- 主卡片 -->
<div
v-else
class="flex flex-col gap-0 rounded-xl border border-gray-200 bg-white shadow-lg dark:border-dk-muted dark:bg-dk-card"
>
<!-- 顶部标题栏 -->
<div class="flex items-center justify-between border-b border-gray-200 px-6 py-4 dark:border-dk-muted">
<h4 class="text-sm font-semibold text-gray-900 dark:text-white">
{{ t("purchase_addorder.edit_order") }}
</h4>
<!-- 返回按钮 -->
<button
class="flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-dk-base"
@click="router.back()"
>
<svg class="h-4 w-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7" />
</svg>
{{ t("purchase.back_to_list") }}
</button>
</div>
<!-- 错误提示字段验证 -->
<div v-if="errors.title" class="mx-6 mt-4 rounded-lg bg-red-50 px-4 py-2 text-sm text-red-600 dark:bg-red-900/20 dark:text-red-400">
{{ errors.title }}
</div>
<!-- 表单主体公共组件 -->
<PurchaseOrderForm
v-model="form"
:initialCosts="initialCosts"
:initialPhotos="initialPhotos"
ref="formRef"
/>
<!-- 底部操作栏 -->
<div class="flex justify-end border-t border-gray-200 px-6 py-4 dark:border-dk-muted">
<button
class="inline-flex items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500/20 disabled:opacity-60"
:disabled="loading"
@click="handleSubmit"
>
<svg v-if="loading" class="h-4 w-4 animate-spin text-white" viewBox="0 0 24 24" fill="none">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg>
{{ t("message.save_ok") }}
</button>
</div>
</div>
</div>
</template>