完善购买和套餐功能
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
<template>
|
||||
<div class="tenant-package-tab" v-loading="loading">
|
||||
<div class="panel-toolbar">
|
||||
<el-button size="small" :loading="loading" @click="refresh">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
刷新数据
|
||||
</el-button>
|
||||
</div>
|
||||
<el-descriptions :column="2" border class="quota-desc">
|
||||
<el-descriptions-item label="当前套餐">
|
||||
<el-select
|
||||
@@ -32,13 +38,27 @@
|
||||
<span v-else class="muted">永久有效</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="开通功能">
|
||||
<template v-if="info.module_names && info.module_names.length">
|
||||
<el-tag v-for="(m, i) in info.module_names" :key="i" size="small" class="module-tag">
|
||||
{{ m }}
|
||||
<template v-if="info.modules && info.modules.length">
|
||||
<el-tag v-for="(m, i) in info.modules" :key="i" size="small" class="module-tag">
|
||||
{{ m.module_name || m.module_code }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<span v-else class="muted">未配置功能</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="单品功能">
|
||||
<template v-if="info.product_modules && info.product_modules.length">
|
||||
<el-tag
|
||||
v-for="(m, i) in info.product_modules"
|
||||
:key="i"
|
||||
size="small"
|
||||
type="success"
|
||||
class="module-tag"
|
||||
>
|
||||
{{ m.module_name || m.module_code }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<span v-else class="muted">无单品购买</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="用户数使用">
|
||||
<span class="quota-text">
|
||||
<b :class="{ danger: info.remaining <= 0 }">{{ info.used }}</b> / {{ info.quota }} 人
|
||||
@@ -52,7 +72,10 @@
|
||||
<span class="muted">剩余 {{ info.remaining }} 个名额</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="增购单价">
|
||||
<span>{{ formatMoney(info.extra_user_price) }}/人</span>
|
||||
<template v-if="Number(info.extra_user_price) > 0">
|
||||
<span>{{ formatMoney(info.extra_user_price) }}/人</span>
|
||||
</template>
|
||||
<span v-else class="muted">未设置</span>
|
||||
<el-button type="primary" link class="ml8" @click="openRecharge">增购用户数</el-button>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
@@ -74,6 +97,51 @@
|
||||
title="该租户套餐即将到期,到期后将自动切换为基础套餐,请及时续费"
|
||||
/>
|
||||
|
||||
<div class="section-title">已购功能(单品购买)</div>
|
||||
<el-table :data="info.product_orders || []" style="width: 100%" size="small">
|
||||
<el-table-column prop="product_name" label="产品" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="功能模块" width="150" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.module_name || row.module_code" size="small" effect="plain">
|
||||
{{ row.module_name || row.module_code }}
|
||||
</el-tag>
|
||||
<span v-else class="muted">未关联</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="order_no" label="订单号" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column label="金额" width="100" align="center">
|
||||
<template #default="{ row }">{{ formatMoney(row.amount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="开通时间" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.activate_time ? formatDate(row.activate_time) : "-" }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="过期时间" min-width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
<template v-if="row.expire_time">
|
||||
<span>{{ formatDate(row.expire_time) }}</span>
|
||||
<el-tag
|
||||
size="small"
|
||||
:type="row.expired ? 'danger' : 'success'"
|
||||
effect="plain"
|
||||
class="ml8"
|
||||
>
|
||||
{{ row.expired ? "已过期" : `剩余 ${remainingDays(row.expire_time)} 天` }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<span v-else class="muted">长期有效</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button size="small" type="danger" link @click="handleCloseEntitlement(row)">
|
||||
关闭功能
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="section-title">增购记录</div>
|
||||
<el-table :data="orders" style="width: 100%" size="small" v-loading="ordersLoading">
|
||||
<el-table-column prop="id" label="ID" width="70" align="center" />
|
||||
@@ -171,7 +239,8 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { formatDateTime } from "@/utils/datetime";
|
||||
import { Refresh } from "@element-plus/icons-vue";
|
||||
import { formatDate, formatDateTime } from "@/utils/datetime";
|
||||
import {
|
||||
getTenantQuotaInfo,
|
||||
getTenantQuotaOrders,
|
||||
@@ -179,6 +248,7 @@ import {
|
||||
setTenantPackage,
|
||||
rechargeTenantQuota,
|
||||
} from "@/api/tenantPackage";
|
||||
import { closeProductOrder } from "@/api/product";
|
||||
|
||||
const props = defineProps<{
|
||||
/** 当前租户 ID,为空时不请求 */
|
||||
@@ -203,6 +273,11 @@ const rechargeForm = ref({
|
||||
});
|
||||
|
||||
const formatMoney = (v: any) => `¥${Number(v || 0).toFixed(2)}`;
|
||||
/** 距到期剩余天数(向上取整,最小 0) */
|
||||
const remainingDays = (t: string) => {
|
||||
const ms = new Date(t).getTime() - Date.now();
|
||||
return Math.max(0, Math.ceil(ms / 86400000));
|
||||
};
|
||||
/** 套餐价格单位随有效时长变化:365天=元/年,30=元/月,90=元/季,其余=元/N天 */
|
||||
const priceUnit = (row: any) => {
|
||||
const d = Number(row?.duration_days || 365);
|
||||
@@ -336,6 +411,32 @@ const handleSetPackage = async (id: number) => {
|
||||
}
|
||||
};
|
||||
|
||||
/** 关闭已开通的单品功能:订单置为已关闭,租户端对应模块权益即时回收 */
|
||||
const handleCloseEntitlement = async (row: any) => {
|
||||
if (!row?.order_id) return;
|
||||
const label = row.module_name || row.product_name || "该";
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`关闭后该租户将立即失去「${label}」功能的使用权限(订单保留,可在「产品定价 - 购买订单」中重新开通),确定继续吗?`,
|
||||
"关闭功能",
|
||||
{ type: "warning", confirmButtonText: "确认关闭" }
|
||||
);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await closeProductOrder(row.order_id);
|
||||
if (res.code === 200) {
|
||||
ElMessage.success("功能已关闭");
|
||||
refresh();
|
||||
} else {
|
||||
ElMessage.error(res.msg || "关闭失败");
|
||||
}
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.message || "关闭失败");
|
||||
}
|
||||
};
|
||||
|
||||
const openRecharge = () => {
|
||||
rechargeForm.value = {
|
||||
type: 1,
|
||||
@@ -391,6 +492,11 @@ defineExpose({ refresh });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.panel-toolbar {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.quota-desc {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user