Files
gao-customer-h5/src/pages/package/PackageConfigDetail.vue
T
2026-09-04 23:07:59 +08:00

218 lines
6.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div v-can="permissionCodes.packageConfig.read" class="package-config-detail">
<template v-if="config">
<section class="hero" v-entrance-transition>
<span class="eyebrow" v-text="'套餐管理'" />
<div class="title"><h1 v-text="config.name || '未命名套餐'" /><t-tag :content="getPackageConfigStatusText(config.status)" variant="light-outline" :theme="getStatusTheme(config.status)" /></div>
<p v-text="config.description || '暂无套餐说明'" />
<div class="hero-meta"><span v-text="`${config.itemList?.length || 0} 项产品权益`" /><strong v-text="formatPackageAmount(config.standardAmount)" /></div>
</section>
<t-cell-group title="基本信息" theme="card" v-entrance-transition="70">
<t-cell title="标准价" :note="formatPackageAmount(config.standardAmount)" />
<t-cell title="起始日期" :note="config.beginAt ? Time.toDateTime(config.beginAt) : '不限'" />
<t-cell title="终止日期" :note="config.endAt ? Time.toDateTime(config.endAt) : '不限'" />
<t-cell title="最后修改人" :note="config.updater?.name || config.updater?.nick || '未知'" />
</t-cell-group>
<t-cell-group title="产品权益" theme="card" v-entrance-transition="140">
<t-cell
v-for="item in config.itemList || []"
:key="item.id || `${item.productId}-${item.productUnitId}`"
:title="item.productNameSnapshot || '未命名产品'"
:note="`${item.defaultQuantity} ${item.unitSnapshot || ''}${item.remark ? `|${item.remark}` : ''}`"
/>
<div v-if="!config.itemList?.length" class="empty" v-text="'暂无产品权益'" />
</t-cell-group>
<t-button
v-if="canPurchase"
class="cell-button"
theme="primary"
content="购买套餐"
@click="toPurchase"
/>
<t-button
v-if="canDelete"
class="cell-button"
theme="danger"
@click="removeConfig"
content="删除"
/>
</template>
<t-empty v-else :description="isLoading ? '正在加载套餐配置' : '套餐配置不存在'" />
</div>
</template>
<script setup lang="ts">
import { DialogPlugin } from "tdesign-mobile-vue";
import { Time } from "timi-web";
import { useUserStore } from "timi-web-api";
import PackageAPI from "@/api/PackageAPI";
import { useCurrentStoreStore } from "@/store/currentStoreStore";
import { useNavBarStore } from "@/store/navBarStore";
import type { GaoPackageConfig, PackageConfigStatus } from "@/types/Package";
import { getErrorMessage } from "@/utils/error";
import { formatPackageAmount, getPackageConfigStatusText } from "@/utils/package";
import { Message } from "@/utils/message";
import { gaoRoleCodes, permissionCodes } from "@/utils/permission";
defineOptions({ name: "PackageConfigDetail" });
const route = useRoute();
const router = useRouter();
const navBarStore = useNavBarStore();
const userStore = useUserStore();
const currentStoreStore = useCurrentStoreStore();
const config = ref<GaoPackageConfig>();
const isLoading = ref(false);
const canUpdate = computed(() => !!config.value && userStore.hasPermissions(permissionCodes.packageConfig.update));
const canDelete = computed(() => !!config.value && userStore.hasPermissions(permissionCodes.packageConfig.delete));
const canPurchase = computed(() =>
!!config.value
&& config.value.status === "ACTIVE"
&& userStore.hasPermissions(permissionCodes.customerPackage.create)
);
function getStatusTheme(status?: PackageConfigStatus): "success" | "warning" | "default" {
return status === "ACTIVE" ? "success" : status === "INACTIVE" ? "warning" : "default";
}
async function loadData(): Promise<void> {
const id = String(route.params.id || "");
if (!id) {
return;
}
isLoading.value = true;
try {
if (userStore.hasRoles(gaoRoleCodes.globalManager)) {
await currentStoreStore.loadStoreList();
} else {
await currentStoreStore.loadLoginStore();
}
config.value = await PackageAPI.configDetail(id);
} catch (error) {
Message.error(getErrorMessage(error, "套餐配置加载失败"));
} finally {
isLoading.value = false;
}
}
async function toEdit(): Promise<void> {
if (config.value?.id && canUpdate.value) {
await router.push(`/management/package-configs/${config.value.id}/edit`);
}
}
async function toPurchase(): Promise<void> {
if (config.value?.id && canPurchase.value) {
await router.push(`/management/package-configs/${config.value.id}/purchase`);
}
}
function removeConfig(): void {
if (!config.value?.id || !canDelete.value) {
return;
}
const dialog = DialogPlugin.confirm({
title: "删除套餐配置",
content: "删除后该配置不再出现在可购买列表中,已购买的客户套餐不受影响。",
confirmBtn: { content: "删除", theme: "danger" },
onConfirm: async () => {
try {
await PackageAPI.configRemove(config.value!.id!);
Message.success("套餐配置已删除");
await router.replace("/management/package-configs");
} catch (error) {
Message.error(getErrorMessage(error, "套餐配置删除失败"));
} finally {
dialog.destroy();
}
}
});
}
onMounted(async () => {
await loadData();
navBarStore.clearRight();
if (canUpdate.value) {
navBarStore.setRightText("编辑", "var(--td-brand-color)", toEdit);
}
});
watch(canUpdate, value => {
navBarStore.clearRight();
if (value) {
navBarStore.setRightText("编辑", "var(--td-brand-color)", toEdit);
}
});
onUnmounted(() => navBarStore.clearRight());
</script>
<style scoped lang="less">
.package-config-detail {
gap: 1rem;
padding: calc(var(--app-nav-height) + 1rem) 0 2rem;
display: flex;
flex-direction: column;
.hero {
margin: 0 1rem;
padding: 1rem;
background: var(--td-bg-color-container);
box-shadow: var(--td-shadow-1);
border-radius: 1rem;
.title {
gap: .5rem;
display: flex;
align-items: center;
justify-content: space-between;
}
.eyebrow {
color: var(--td-brand-color);
display: block;
font-size: .6875rem;
font-weight: 700;
letter-spacing: .08em;
}
h1 {
margin: 0;
font-size: 1.25rem;
line-height: 1.35;
}
p {
color: var(--td-text-color-secondary);
margin: .5rem 0 0;
line-height: 1.5;
}
.hero-meta {
gap: .75rem;
display: flex;
margin-top: .75rem;
color: var(--td-text-color-secondary);
align-items: center;
justify-content: space-between;
}
strong {
color: #c2410c;
font-size: 1.2rem;
white-space: nowrap;
}
}
}
:global(html.theme-dark) .package-config-detail .hero {
.eyebrow {
color: #99f6e4;
}
strong {
color: #fdba74;
}
}
</style>