wip(freight): migration 0017 + model/column-list groundwork for add-freight-templates

This commit is contained in:
Chengdong Zhang
2026-09-23 17:39:45 +08:00
parent a83e857bdf
commit 5b426486ac
105 changed files with 6193 additions and 1566 deletions
+16 -18
View File
@@ -244,10 +244,7 @@ export interface ApiClient {
getAftersale(id: string): Promise<AftersaleDetail>;
cancelAftersale(id: string): Promise<Aftersale>;
reopenAftersale(id: string): Promise<Aftersale>;
submitAftersaleReturnTracking(
id: string,
body: AftersaleReturnTrackingBody,
): Promise<Aftersale>;
submitAftersaleReturnTracking(id: string, body: AftersaleReturnTrackingBody): Promise<Aftersale>;
addAftersaleMessage(id: string, body: AftersaleMessageBody): Promise<AftersaleMessage>;
/** Public points catalog: published products only. */
listPointsProducts(): Promise<IntegralProduct[]>;
@@ -451,27 +448,28 @@ export function createApi(opts: ApiClientOptions): ApiClient {
listOrders: (page = 1) => r("GET", "/admin/orders", undefined, { page }),
listCurrencies: () => r("GET", "/admin/currencies"),
upsertCurrency: (body) => r("POST", "/admin/currencies", body),
setRate: (code, rateToBase) => r("PUT", `/admin/currencies/${code}/rate`, {
rate_to_base: rateToBase,
}),
setRate: (code, rateToBase) =>
r("PUT", `/admin/currencies/${code}/rate`, {
rate_to_base: rateToBase,
}),
getContent: () => r("GET", "/admin/content"),
replaceContent: (kind, items) => r("PUT", `/admin/content/${kind}`, items),
setShopProfile: (id, body) => r("PUT", `/admin/shops/${id}/profile`, body),
/** Replaces the whole ordered brand list. */
getBrands: () => r("GET", "/brands"),
replaceBrands: (items) => r("PUT", "/admin/brands", items),
/** Replaces the whole ordered brand list. */
getBrands: () => r("GET", "/brands"),
replaceBrands: (items) => r("PUT", "/admin/brands", items),
listAftersales: (status) => r("GET", "/admin/aftersales", undefined, { status }),
getAftersale: (id) => r("GET", `/admin/aftersales/${id}`),
arbitrateAftersale: (id, outcome) =>
r("POST", `/admin/aftersales/${id}/arbitrate`, { outcome }),
listPointsProducts: () => r("GET", "/admin/points/products"),
createPointsProduct: (body) => r("POST", "/admin/points/products", body),
updatePointsProduct: (id, body) => r("PUT", `/admin/points/products/${id}`, body),
setPointsProductPublished: (id, published) =>
r("POST", `/admin/points/products/${id}/${published ? "publish" : "unpublish"}`),
listPointsRedemptions: (page = 1) => r("GET", "/admin/points/orders", undefined, { page }),
fulfillRedemption: (id) => r("POST", `/admin/points/orders/${id}/fulfill`),
cancelRedemption: (id) => r("POST", `/admin/points/orders/${id}/cancel`),
listPointsProducts: () => r("GET", "/admin/points/products"),
createPointsProduct: (body) => r("POST", "/admin/points/products", body),
updatePointsProduct: (id, body) => r("PUT", `/admin/points/products/${id}`, body),
setPointsProductPublished: (id, published) =>
r("POST", `/admin/points/products/${id}/${published ? "publish" : "unpublish"}`),
listPointsRedemptions: (page = 1) => r("GET", "/admin/points/orders", undefined, { page }),
fulfillRedemption: (id) => r("POST", `/admin/points/orders/${id}/fulfill`),
cancelRedemption: (id) => r("POST", `/admin/points/orders/${id}/cancel`),
},
};
}
+3 -2
View File
@@ -26,8 +26,9 @@
--radius-sm: 4px;
--radius-md: 8px;
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Helvetica Neue", Arial, "PingFang SC", "Microsoft YaHei", sans-serif;
--font-sans:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC",
"Microsoft YaHei", sans-serif;
/* Spec-locked mall sizes: max-w-mall, h-hero */
--container-mall: 1200px;
+3 -8
View File
@@ -130,12 +130,7 @@ export interface Cart {
}
export type OrderStatus =
| "pending_payment"
| "paid"
| "fulfilling"
| "shipped"
| "completed"
| "cancelled";
"pending_payment" | "paid" | "fulfilling" | "shipped" | "completed" | "cancelled";
export interface OrderItem {
id: string;
@@ -467,7 +462,8 @@ export interface GroupBuyIntent {
group_id?: string | null;
}
export type ShipmentStatus = "pending" | "shipped" | "delivered";export interface Shipment {
export type ShipmentStatus = "pending" | "shipped" | "delivered";
export interface Shipment {
id: string;
shipment_no: string;
order_id: string;
@@ -699,4 +695,3 @@ export interface AftersaleReturnTrackingBody {
}
export type AftersaleArbitration = "refund" | "reject";
+4 -10
View File
@@ -1,8 +1,7 @@
<script setup lang="ts">
const props = withDefaults(
defineProps<{ tone?: "green" | "blue" | "orange" | "red" | "gray" }>(),
{ tone: "gray" },
);
const props = withDefaults(defineProps<{ tone?: "green" | "blue" | "orange" | "red" | "gray" }>(), {
tone: "gray",
});
const tones = {
green: "bg-success/10 text-success",
@@ -14,12 +13,7 @@ const tones = {
</script>
<template>
<span
:class="[
'inline-block rounded px-2 py-0.5 text-xs font-medium',
tones[props.tone],
]"
>
<span :class="['inline-block rounded px-2 py-0.5 text-xs font-medium', tones[props.tone]]">
<slot />
</span>
</template>
+1 -6
View File
@@ -3,12 +3,7 @@ const props = withDefaults(defineProps<{ padded?: boolean }>(), { padded: true }
</script>
<template>
<div
:class="[
'rounded-lg border border-border bg-surface shadow-sm',
props.padded ? 'p-5' : '',
]"
>
<div :class="['border-border bg-surface rounded-lg border shadow-sm', props.padded ? 'p-5' : '']">
<slot />
</div>
</template>
+2 -2
View File
@@ -4,8 +4,8 @@ defineProps<{ label?: string; error?: string }>();
<template>
<div class="mb-3.5">
<label v-if="label" class="mb-1 block text-sm font-medium text-text">{{ label }}</label>
<label v-if="label" class="text-text mb-1 block text-sm font-medium">{{ label }}</label>
<slot />
<p v-if="error" class="mt-1 text-sm text-danger">{{ error }}</p>
<p v-if="error" class="text-danger mt-1 text-sm">{{ error }}</p>
</div>
</template>
+5 -5
View File
@@ -1,8 +1,8 @@
<script setup lang="ts">
withDefaults(
defineProps<{ type?: string; placeholder?: string; disabled?: boolean }>(),
{ type: "text", disabled: false },
);
withDefaults(defineProps<{ type?: string; placeholder?: string; disabled?: boolean }>(), {
type: "text",
disabled: false,
});
const model = defineModel<string | number>();
</script>
@@ -12,6 +12,6 @@ const model = defineModel<string | number>();
:type="type"
:placeholder="placeholder"
:disabled="disabled"
class="w-full rounded-md border border-border bg-surface px-3 py-2 text-sm text-text focus:border-primary focus:outline-2 focus:outline-primary/30 disabled:opacity-50"
class="border-border bg-surface text-text focus:border-primary focus:outline-primary/30 w-full rounded-md border px-3 py-2 text-sm focus:outline-2 disabled:opacity-50"
/>
</template>
+1 -1
View File
@@ -5,7 +5,7 @@ defineProps<{ title?: string }>();
<template>
<div class="py-6 pb-12">
<div v-if="title || $slots.actions" class="mb-4 flex items-center justify-between">
<h1 class="text-xl font-bold text-text">{{ title }}</h1>
<h1 class="text-text text-xl font-bold">{{ title }}</h1>
<slot name="actions" />
</div>
<slot />
+3 -3
View File
@@ -3,12 +3,12 @@ defineProps<{ title?: string }>();
</script>
<template>
<div class="rounded-lg border border-border bg-surface shadow-sm">
<div class="border-border bg-surface rounded-lg border shadow-sm">
<div
v-if="title || $slots.actions"
class="flex items-center justify-between border-b border-border px-5 py-3"
class="border-border flex items-center justify-between border-b px-5 py-3"
>
<h3 class="text-sm font-semibold text-text">{{ title }}</h3>
<h3 class="text-text text-sm font-semibold">{{ title }}</h3>
<slot name="actions" />
</div>
<div class="p-5"><slot /></div>
+2 -2
View File
@@ -1,7 +1,7 @@
<template>
<div class="overflow-x-auto rounded-lg border border-border bg-surface shadow-sm">
<div class="border-border bg-surface overflow-x-auto rounded-lg border shadow-sm">
<table
class="w-full border-collapse [&_td]:border-b [&_td]:border-border [&_td]:px-3 [&_td]:py-2.5 [&_td]:text-left [&_td]:text-sm [&_th]:border-b [&_th]:border-border [&_th]:px-3 [&_th]:py-2.5 [&_th]:text-left [&_th]:text-[13px] [&_th]:font-semibold [&_th]:text-muted [&_tr:last-child_td]:border-b-0"
class="[&_td]:border-border [&_th]:border-border [&_th]:text-muted w-full border-collapse [&_td]:border-b [&_td]:px-3 [&_td]:py-2.5 [&_td]:text-left [&_td]:text-sm [&_th]:border-b [&_th]:px-3 [&_th]:py-2.5 [&_th]:text-left [&_th]:text-[13px] [&_th]:font-semibold [&_tr:last-child_td]:border-b-0"
>
<slot />
</table>
+1 -2
View File
@@ -6,8 +6,7 @@ export type Accent = (typeof ACCENTS)[number];
const STORAGE_KEY = "vmall-accent";
const valid = (value: string | null): value is Accent =>
ACCENTS.includes(value as Accent);
const valid = (value: string | null): value is Accent => ACCENTS.includes(value as Accent);
/**
* Console accent preset state. `boot()` belongs in the console shell setup: