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
+72 -23
View File
@@ -187,36 +187,70 @@ onMounted(async () => {
<template>
<VPage :title="$t('shop.groupBuyingList')">
<div v-if="error" class="my-2 text-sm text-danger" role="alert">{{ error }}</div>
<div v-if="message" class="my-2 text-sm text-muted" role="status">{{ message }}</div>
<div v-if="error" class="text-danger my-2 text-sm" role="alert">{{ error }}</div>
<div v-if="message" class="text-muted my-2 text-sm" role="status">{{ message }}</div>
<VCard class="mb-5">
<h2 class="mb-4 text-base font-semibold">{{ editingId ? $t("shop.editGroupActivity") : $t("shop.newGroupActivity") }}</h2>
<div class="my-3 grid gap-3 [grid-template-columns:repeat(auto-fit,minmax(220px,1fr))]">
<h2 class="mb-4 text-base font-semibold">
{{ editingId ? $t("shop.editGroupActivity") : $t("shop.newGroupActivity") }}
</h2>
<div class="my-3 grid [grid-template-columns:repeat(auto-fit,minmax(220px,1fr))] gap-3">
<VField :label="$t('shop.groupSku')">
<select v-model="form.skuId" 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">
<select
v-model="form.skuId"
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"
>
<option value="">{{ $t("shop.flashSelectSku") }}</option>
<option v-for="option in skuOptions" :key="option.id" :value="option.id">{{ option.label }}</option>
<option v-for="option in skuOptions" :key="option.id" :value="option.id">
{{ option.label }}
</option>
</select>
</VField>
<VField :label="$t('shop.groupNameEn')"><VInput v-model="form.nameEn" type="text" /></VField>
<VField :label="$t('shop.groupNameZh')"><VInput v-model="form.nameZh" type="text" /></VField>
<VField :label="$t('shop.groupDescriptionEn')"><VInput v-model="form.descriptionEn" type="text" /></VField>
<VField :label="$t('shop.groupDescriptionZh')"><VInput v-model="form.descriptionZh" type="text" /></VField>
<VField :label="$t('shop.groupPrice')"><VInput v-model.number="form.groupPriceMinor" type="number" min="1" step="1" /></VField>
<VField :label="$t('shop.groupNameEn')"
><VInput v-model="form.nameEn" type="text"
/></VField>
<VField :label="$t('shop.groupNameZh')"
><VInput v-model="form.nameZh" type="text"
/></VField>
<VField :label="$t('shop.groupDescriptionEn')"
><VInput v-model="form.descriptionEn" type="text"
/></VField>
<VField :label="$t('shop.groupDescriptionZh')"
><VInput v-model="form.descriptionZh" type="text"
/></VField>
<VField :label="$t('shop.groupPrice')"
><VInput v-model.number="form.groupPriceMinor" type="number" min="1" step="1"
/></VField>
<VField :label="$t('shop.couponCurrency')">
<select v-model="form.currency" 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">
<select
v-model="form.currency"
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"
>
<option v-for="c in currencies" :key="c.code" :value="c.code">{{ c.code }}</option>
</select>
</VField>
<VField :label="$t('shop.groupRequiredMembers')"><VInput v-model.number="form.requiredMembers" type="number" min="2" step="1" /></VField>
<VField :label="$t('shop.groupLifetimeHours')"><VInput v-model.number="form.groupLifetimeHours" type="number" min="1" step="1" /></VField>
<VField :label="$t('shop.groupStartsAt')"><VInput v-model="form.startsAt" type="datetime-local" /></VField>
<VField :label="$t('shop.groupEndsAt')"><VInput v-model="form.endsAt" type="datetime-local" /></VField>
<label class="flex items-center gap-2 text-sm font-medium text-text"><input v-model="form.enabled" type="checkbox" class="h-4 w-4 accent-primary" /><span>{{ $t("shop.groupEnabled") }}</span></label>
<VField :label="$t('shop.groupRequiredMembers')"
><VInput v-model.number="form.requiredMembers" type="number" min="2" step="1"
/></VField>
<VField :label="$t('shop.groupLifetimeHours')"
><VInput v-model.number="form.groupLifetimeHours" type="number" min="1" step="1"
/></VField>
<VField :label="$t('shop.groupStartsAt')"
><VInput v-model="form.startsAt" type="datetime-local"
/></VField>
<VField :label="$t('shop.groupEndsAt')"
><VInput v-model="form.endsAt" type="datetime-local"
/></VField>
<label class="text-text flex items-center gap-2 text-sm font-medium"
><input v-model="form.enabled" type="checkbox" class="accent-primary h-4 w-4" /><span>{{
$t("shop.groupEnabled")
}}</span></label
>
</div>
<div class="flex gap-2">
<VBtn variant="primary" :disabled="saving" @click="save">{{ editingId ? $t("shop.updateGroupActivity") : $t("shop.createGroupActivity") }}</VBtn>
<VBtn variant="primary" :disabled="saving" @click="save">{{
editingId ? $t("shop.updateGroupActivity") : $t("shop.createGroupActivity")
}}</VBtn>
<VBtn v-if="editingId" type="button" @click="resetForm">{{ $t("common.cancel") }}</VBtn>
</div>
</VCard>
@@ -247,16 +281,31 @@ onMounted(async () => {
<td>{{ activity.starts_at.slice(0, 10) }}</td>
<td>
<template v-if="activity.open_groups.length">
<VBadge v-for="group in activity.open_groups" :key="group.id" tone="orange" class="mr-1">
{{ $t("shop.groupPaidMembers") }} {{ group.paid_member_count }}/{{ group.required_members }}
<VBadge
v-for="group in activity.open_groups"
:key="group.id"
tone="orange"
class="mr-1"
>
{{ $t("shop.groupPaidMembers") }} {{ group.paid_member_count }}/{{
group.required_members
}}
</VBadge>
</template>
<span v-else class="text-muted">{{ $t("shop.groupNoOpenGroups") }}</span>
</td>
<td><VBadge :tone="activity.enabled ? 'green' : 'red'">{{ activity.enabled ? $t("shop.enabledOn") : $t("shop.enabledOff") }}</VBadge></td>
<td>
<VBadge :tone="activity.enabled ? 'green' : 'red'">{{
activity.enabled ? $t("shop.enabledOn") : $t("shop.enabledOff")
}}</VBadge>
</td>
<td class="flex gap-1.5">
<VBtn size="sm" :disabled="actionId === activity.id" @click="edit(activity)">{{ $t("shop.edit") }}</VBtn>
<VBtn size="sm" :disabled="actionId === activity.id" @click="remove(activity)">{{ $t("common.delete") }}</VBtn>
<VBtn size="sm" :disabled="actionId === activity.id" @click="edit(activity)">{{
$t("shop.edit")
}}</VBtn>
<VBtn size="sm" :disabled="actionId === activity.id" @click="remove(activity)">{{
$t("common.delete")
}}</VBtn>
</td>
</tr>
</tbody>