Merge branch 'master' of https://git.yunzer.cn/yunzerwebsite/yunzerwebsiteallinone
This commit is contained in:
@@ -75,7 +75,10 @@
|
||||
@click="handleNavigate(module)"
|
||||
>
|
||||
<div class="card-header">
|
||||
<span class="card-title">{{ module.name }}</span>
|
||||
<span class="card-title">
|
||||
{{ module.name }}
|
||||
<el-icon v-if="module.locked" class="lock-badge"><Lock /></el-icon>
|
||||
</span>
|
||||
<div class="card-icon-wrapper" v-html="module.icon"></div>
|
||||
</div>
|
||||
<div class="card-divider"></div>
|
||||
@@ -117,7 +120,10 @@
|
||||
@click="handleNavigate(module)"
|
||||
>
|
||||
<div class="card-header">
|
||||
<span class="card-title">{{ module.name }}</span>
|
||||
<span class="card-title">
|
||||
{{ module.name }}
|
||||
<el-icon v-if="module.locked" class="lock-badge"><Lock /></el-icon>
|
||||
</span>
|
||||
<div class="card-icon-wrapper" v-html="module.icon"></div>
|
||||
</div>
|
||||
<div class="card-divider"></div>
|
||||
@@ -159,7 +165,10 @@
|
||||
@click="handleNavigate(module)"
|
||||
>
|
||||
<div class="card-header">
|
||||
<span class="card-title">{{ module.name }}</span>
|
||||
<span class="card-title">
|
||||
{{ module.name }}
|
||||
<el-icon v-if="module.locked" class="lock-badge"><Lock /></el-icon>
|
||||
</span>
|
||||
<div class="card-icon-wrapper" v-html="module.icon"></div>
|
||||
</div>
|
||||
<div class="card-divider"></div>
|
||||
@@ -206,7 +215,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, onMounted } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
|
||||
import {
|
||||
ArrowDown,
|
||||
@@ -218,6 +227,7 @@ import {
|
||||
Moon,
|
||||
OfficeBuilding,
|
||||
Lock,
|
||||
Lock,
|
||||
} from "@element-plus/icons-vue";
|
||||
|
||||
import { getTenantList } from "@/api/modules";
|
||||
@@ -243,15 +253,22 @@ const router = useRouter();
|
||||
const authStore = useAuthStore();
|
||||
const menuStore = useMenuStore();
|
||||
|
||||
// 已开通模块排在前面,套餐未开通(锁定)的模块沉到后方
|
||||
function sortUnlockedFirst(list: ModuleItem[]): ModuleItem[] {
|
||||
return [...list].sort(
|
||||
(a, b) => Number(!!a.locked) - Number(!!b.locked)
|
||||
);
|
||||
}
|
||||
|
||||
// 根据type分组模块
|
||||
const basicModules = computed(() =>
|
||||
moduleList.value.filter((item) => item.type === 1)
|
||||
sortUnlockedFirst(moduleList.value.filter((item) => item.type === 1))
|
||||
);
|
||||
const systemModules = computed(() =>
|
||||
moduleList.value.filter((item) => item.type === 2)
|
||||
sortUnlockedFirst(moduleList.value.filter((item) => item.type === 2))
|
||||
);
|
||||
const uncategorizedModules = computed(() =>
|
||||
moduleList.value.filter((item) => item.type === 0)
|
||||
sortUnlockedFirst(moduleList.value.filter((item) => item.type === 0))
|
||||
);
|
||||
|
||||
const moduleList = ref<ModuleItem[]>([]);
|
||||
@@ -327,6 +344,25 @@ const fetchUserProfile = async () => {
|
||||
// 当前租户(企业)名称,来自后端 /backend/getCurrentUser 或登录接口返回的 tenant_name
|
||||
const tenantName = computed(() => authStore.user?.tenant_name || "");
|
||||
|
||||
// 当前租户生效套餐名称(用于未开通提示)
|
||||
const packageName = ref("");
|
||||
// 套餐购买链接(平台端配置,为空时点击「购买」仅提示联系管理员)
|
||||
const purchaseUrl = ref("");
|
||||
|
||||
// 套餐未开通模块:不跳转,提示购买套餐后使用
|
||||
function showLockedTip(module: ModuleItem) {
|
||||
const pkg = packageName.value ? `「${packageName.value}」` : "当前";
|
||||
ElMessageBox.alert(
|
||||
`${pkg}套餐未包含「${module.name}」功能模块,请购买或升级套餐后使用。如有疑问请联系平台管理员。`,
|
||||
"功能未开通",
|
||||
{
|
||||
confirmButtonText: "我知道了",
|
||||
type: "warning",
|
||||
customClass: "module-locked-tip"
|
||||
}
|
||||
).catch(() => {});
|
||||
}
|
||||
|
||||
// 处理导航跳转
|
||||
function handleNavigate(module: ModuleItem) {
|
||||
if (module.enabled === false) {
|
||||
@@ -657,7 +693,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.module-card {
|
||||
height: 180px;
|
||||
min-height: 180px;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 30px;
|
||||
@@ -683,9 +719,17 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.card-title {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: @text-main;
|
||||
|
||||
.lock-badge {
|
||||
font-size: 14px;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -708,6 +752,79 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.card-lock-tip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
font-size: 12px;
|
||||
color: #c0c4cc;
|
||||
|
||||
.buy-btn {
|
||||
flex-shrink: 0;
|
||||
padding: 2px 10px;
|
||||
border: 1px solid #3973ff;
|
||||
border-radius: 12px;
|
||||
color: #3973ff;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: #3973ff;
|
||||
border-color: #3973ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 套餐未开通模块:置灰 + 禁止点击效果
|
||||
&.is-locked {
|
||||
background: #fafafa;
|
||||
border-style: dashed;
|
||||
border-color: #dcdfe6;
|
||||
box-shadow: none;
|
||||
cursor: not-allowed;
|
||||
filter: grayscale(1);
|
||||
opacity: 0.8;
|
||||
|
||||
.card-title {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.card-desc {
|
||||
color: #a8abb2;
|
||||
}
|
||||
|
||||
.card-icon-wrapper {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.card-divider {
|
||||
border-color: #e4e7ed;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: none;
|
||||
background: #fafafa;
|
||||
box-shadow: none;
|
||||
|
||||
.card-title,
|
||||
.card-desc {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.card-icon-wrapper {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.card-divider {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 8px 24px rgba(102, 126, 234, 0.15);
|
||||
@@ -1140,6 +1257,19 @@ onMounted(() => {
|
||||
.modules-section .module-card .card-desc {
|
||||
color: #8c8c8c !important;
|
||||
}
|
||||
|
||||
.modules-section .module-card.is-locked {
|
||||
background: #1f1f1f;
|
||||
|
||||
.card-title {
|
||||
color: #8c8c8c !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.card-desc {
|
||||
color: #6b6b6b !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user