更新模块市场功能
This commit is contained in:
parent
992b7e571b
commit
df0507ed2f
11
docs/拼接接口路径.md
Normal file
11
docs/拼接接口路径.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
//拼接接口路径
|
||||||
|
const getEnvUrl = (path: string) => {
|
||||||
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
||||||
|
return `${API_BASE_URL}${path}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
用例:
|
||||||
|
<img :src="getEnvUrl(module.thumb)" :alt="module.title" />
|
||||||
|
|
||||||
|
|
||||||
|
const url = getEnvUrl('/admin/moduleCenter/modules');
|
||||||
@ -1,7 +1,8 @@
|
|||||||
<el-form-item label="默认图片" prop="image">
|
<el-form-item label="默认图片" prop="image">
|
||||||
<div class="uploads">
|
<div class="uploads">
|
||||||
<el-upload v-model:file-list="fileList" :action="uploadUrl" list-type="picture-card" :headers="uploadHeaders"
|
<el-upload v-model:file-list="fileList" :action="uploadUrl" list-type="picture-card"
|
||||||
:limit="1" :auto-upload="false" :before-upload="beforeImgUpload" :on-success="handleImgSuccess">
|
:headers="uploadHeaders" :limit="1" :auto-upload="false" :before-upload="beforeImgUpload"
|
||||||
|
:on-success="handleImgSuccess">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<Plus />
|
<Plus />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
@ -34,7 +35,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
|
||||||
import { uploadFile } from '@/api/file.js';
|
import { uploadFile } from '@/api/file.js';
|
||||||
import { ElMessage, ElUpload } from 'element-plus'
|
import { ElMessage, ElUpload } from 'element-plus'
|
||||||
|
|
||||||
|
|||||||
57
src/api/moduleCenter.js
Normal file
57
src/api/moduleCenter.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import request from "@/utils/request";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模块中心分类
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
export function getModuleCategory() {
|
||||||
|
return request({
|
||||||
|
url: "/admin/moduleCategory",
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模块中心列表
|
||||||
|
* @param {number} cid 分类id
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
export function getModules(cid) {
|
||||||
|
return request({
|
||||||
|
url: "/admin/moduleCenter/modules",
|
||||||
|
method: "get",
|
||||||
|
params: { cid }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑模块分类
|
||||||
|
* @param {Object} data 分类数据
|
||||||
|
* @param {number} data.id 分类id(编辑时必填,新增时不填)
|
||||||
|
* @param {string} data.title 分类名称
|
||||||
|
* @param {number} data.status 分类状态
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
export function editModuleCategory(data) {
|
||||||
|
return request({
|
||||||
|
url: "/admin/moduleCenter/editCategory",
|
||||||
|
method: "post",
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑模块
|
||||||
|
* @param {Object} data 模块数据
|
||||||
|
* @param {number} data.id 模块id(编辑时必填,新增时不填)
|
||||||
|
* @param {string} data.title 模块名称
|
||||||
|
* @param {number} data.status 模块状态
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
export function editModules(data) {
|
||||||
|
return request({
|
||||||
|
url: "/admin/moduleCenter/editModules",
|
||||||
|
method: "post",
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -54,26 +54,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="home-wrapper">
|
<div class="home-wrapper">
|
||||||
<!-- <div class="welcome-section">
|
|
||||||
<div class="welcome-content">
|
|
||||||
<h1 class="welcome-title">
|
|
||||||
<span class="greeting">您好,</span>
|
|
||||||
<span class="username">{{ userName }}</span>
|
|
||||||
</h1>
|
|
||||||
<p class="welcome-subtitle">欢迎进入系统管理平台</p>
|
|
||||||
<p class="welcome-desc">选择下方功能模块开始管理您的系统</p>
|
|
||||||
</div>
|
|
||||||
<div class="welcome-decoration">
|
|
||||||
<div class="decoration-circle circle-1"></div>
|
|
||||||
<div class="decoration-circle circle-2"></div>
|
|
||||||
<div class="decoration-circle circle-3"></div>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<div class="modules-section" v-if="moduleList.length > 0">
|
<div class="modules-section" v-if="moduleList.length > 0">
|
||||||
|
<!-- 功能模块 (type=1) -->
|
||||||
|
<div v-if="basicModules.length > 0" class="category-section">
|
||||||
|
<div class="category-title">功能模块</div>
|
||||||
<div class="module-grid">
|
<div class="module-grid">
|
||||||
<div
|
<div
|
||||||
v-for="module in moduleList"
|
v-for="module in basicModules"
|
||||||
:key="module.path"
|
:key="module.path"
|
||||||
class="module-card"
|
class="module-card"
|
||||||
@click="handleNavigate(module.path)"
|
@click="handleNavigate(module.path)"
|
||||||
@ -90,6 +77,51 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 系统设置 (type=2) -->
|
||||||
|
<div v-if="systemModules.length > 0" class="category-section">
|
||||||
|
<div class="category-title">系统设置</div>
|
||||||
|
<div class="module-grid">
|
||||||
|
<div
|
||||||
|
v-for="module in systemModules"
|
||||||
|
:key="module.path"
|
||||||
|
class="module-card"
|
||||||
|
@click="handleNavigate(module.path)"
|
||||||
|
>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="card-title">{{ module.name }}</span>
|
||||||
|
<div class="card-icon-wrapper" v-html="module.icon"></div>
|
||||||
|
</div>
|
||||||
|
<div class="card-divider"></div>
|
||||||
|
<div class="card-content">
|
||||||
|
<p class="card-desc">{{ module.description || "暂无描述" }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 未分类 (type=0) -->
|
||||||
|
<div v-if="uncategorizedModules.length > 0" class="category-section">
|
||||||
|
<div class="category-title">未分类</div>
|
||||||
|
<div class="module-grid">
|
||||||
|
<div
|
||||||
|
v-for="module in uncategorizedModules"
|
||||||
|
:key="module.path"
|
||||||
|
class="module-card"
|
||||||
|
@click="handleNavigate(module.path)"
|
||||||
|
>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="card-title">{{ module.name }}</span>
|
||||||
|
<div class="card-icon-wrapper" v-html="module.icon"></div>
|
||||||
|
</div>
|
||||||
|
<div class="card-divider"></div>
|
||||||
|
<div class="card-content">
|
||||||
|
<p class="card-desc">{{ module.description || "暂无描述" }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-else class="empty-state">
|
<div v-else class="empty-state">
|
||||||
<el-icon :size="64" class="empty-icon"><Grid /></el-icon>
|
<el-icon :size="64" class="empty-icon"><Grid /></el-icon>
|
||||||
<p class="empty-text">暂无功能模块</p>
|
<p class="empty-text">暂无功能模块</p>
|
||||||
@ -127,12 +159,25 @@ interface ModuleItem {
|
|||||||
description: string;
|
description: string;
|
||||||
sort: number;
|
sort: number;
|
||||||
status: number;
|
status: number;
|
||||||
|
type: number;
|
||||||
|
title?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const menuStore = useMenuStore();
|
const menuStore = useMenuStore();
|
||||||
|
|
||||||
|
// 根据type分组模块
|
||||||
|
const basicModules = computed(() =>
|
||||||
|
moduleList.value.filter((item) => item.type === 1)
|
||||||
|
);
|
||||||
|
const systemModules = computed(() =>
|
||||||
|
moduleList.value.filter((item) => item.type === 2)
|
||||||
|
);
|
||||||
|
const uncategorizedModules = computed(() =>
|
||||||
|
moduleList.value.filter((item) => item.type === 0)
|
||||||
|
);
|
||||||
|
|
||||||
const moduleList = ref<ModuleItem[]>([]);
|
const moduleList = ref<ModuleItem[]>([]);
|
||||||
const refreshLoading = ref(false);
|
const refreshLoading = ref(false);
|
||||||
|
|
||||||
@ -231,7 +276,12 @@ async function loadModules() {
|
|||||||
const list = res.data?.list || [];
|
const list = res.data?.list || [];
|
||||||
moduleList.value = list
|
moduleList.value = list
|
||||||
.filter((item: ModuleItem) => item.status === 1 && item.is_show === 1)
|
.filter((item: ModuleItem) => item.status === 1 && item.is_show === 1)
|
||||||
.sort((a, b) => Number(a.sort) - Number(b.sort));
|
.sort((a, b) => Number(a.sort) - Number(b.sort))
|
||||||
|
.map((item: ModuleItem) => ({
|
||||||
|
...item,
|
||||||
|
type: item.type || 0, // 默认为0(未分类)
|
||||||
|
title: item.name // 添加title字段用于显示分类标题
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("加载模块列表失败:", error);
|
console.error("加载模块列表失败:", error);
|
||||||
@ -416,14 +466,27 @@ $text-regular: #606266;
|
|||||||
.modules-section {
|
.modules-section {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
|
||||||
|
.category-section {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
|
||||||
|
.category-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-main;
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
padding-left: 4px;
|
||||||
|
border-left: 4px solid #667eea;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.module-grid {
|
.module-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(5, 1fr);
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-card {
|
.module-card {
|
||||||
height: 220px;
|
height: 180px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
@ -468,7 +531,7 @@ $text-regular: #606266;
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
-webkit-line-clamp: 2;
|
-webkit-line-clamp: 3;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|||||||
313
src/views/moduleshop/category/index.vue
Normal file
313
src/views/moduleshop/category/index.vue
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
<template>
|
||||||
|
<div class="category-container">
|
||||||
|
<el-card shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>分类管理</span>
|
||||||
|
<el-button type="primary" :icon="Plus" @click="handleCategoryAdd">
|
||||||
|
新增分类
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table
|
||||||
|
:data="categoryList"
|
||||||
|
v-loading="loading"
|
||||||
|
stripe
|
||||||
|
border
|
||||||
|
>
|
||||||
|
<el-table-column prop="id" label="ID" width="80" />
|
||||||
|
<el-table-column prop="title" label="分类标题" min-width="200" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="status" label="状态" width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="getStatusType(row.status)">
|
||||||
|
{{ getStatusText(row.status) }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="200" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
link
|
||||||
|
size="small"
|
||||||
|
:icon="Edit"
|
||||||
|
@click="handleEdit(row)"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
link
|
||||||
|
size="small"
|
||||||
|
:icon="Delete"
|
||||||
|
@click="handleDelete(row)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<div v-if="categoryList.length === 0 && !loading" class="empty-state">
|
||||||
|
<el-empty description="暂无分类记录" />
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
v-model="categoryDialogVisible"
|
||||||
|
:title="isEdit ? '编辑分类' : '新增分类'"
|
||||||
|
width="700px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@close="handleCategoryClose"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="formData"
|
||||||
|
:rules="formRules"
|
||||||
|
label-width="120px"
|
||||||
|
>
|
||||||
|
<el-form-item label="分类标题" prop="title">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.title"
|
||||||
|
placeholder="请输入分类标题"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="状态" prop="status">
|
||||||
|
<el-radio-group v-model="formData.status">
|
||||||
|
<el-radio :value="1">启用</el-radio>
|
||||||
|
<el-radio :value="0">禁用</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="categoryDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">
|
||||||
|
确定
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, onMounted } from "vue";
|
||||||
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
|
import { Plus, Edit, Delete } from "@element-plus/icons-vue";
|
||||||
|
import type { FormInstance, FormRules } from "element-plus";
|
||||||
|
|
||||||
|
import { getModuleCategory,editModuleCategory } from "@/api/moduleCenter";
|
||||||
|
|
||||||
|
interface Category {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
module_name: string;
|
||||||
|
module_id?: number;
|
||||||
|
status: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ModuleOption {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
const categoryList = ref<Category[]>([]);
|
||||||
|
const categoryDialogVisible = ref(false);
|
||||||
|
const submitLoading = ref(false);
|
||||||
|
const isEdit = ref(false);
|
||||||
|
const editId = ref<number>(0);
|
||||||
|
|
||||||
|
const formRef = ref<FormInstance>();
|
||||||
|
|
||||||
|
const formData = reactive({
|
||||||
|
title: "",
|
||||||
|
module_id: null as number | null,
|
||||||
|
status: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
const moduleOptions = ref<ModuleOption[]>([]);
|
||||||
|
|
||||||
|
const formRules: FormRules = {
|
||||||
|
title: [
|
||||||
|
{ required: true, message: "请输入分类标题", trigger: "blur" }
|
||||||
|
],
|
||||||
|
module_id: [
|
||||||
|
{ required: true, message: "请选择所属模块", trigger: "change" }
|
||||||
|
],
|
||||||
|
status: [
|
||||||
|
{ required: true, message: "请选择状态", trigger: "change" }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStatusText = (status: number) => {
|
||||||
|
const map: Record<number, string> = {
|
||||||
|
0: "禁用",
|
||||||
|
1: "启用"
|
||||||
|
};
|
||||||
|
return map[status] || "未知";
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStatusType = (status: number) => {
|
||||||
|
const map: Record<number, any> = {
|
||||||
|
0: "info",
|
||||||
|
1: "success",
|
||||||
|
2: "warning"
|
||||||
|
};
|
||||||
|
return map[status] || "info";
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatDate = (date: string) => {
|
||||||
|
if (!date) return "-";
|
||||||
|
const d = new Date(date);
|
||||||
|
const year = d.getFullYear();
|
||||||
|
const month = String(d.getMonth() + 1).padStart(2, "0");
|
||||||
|
const day = String(d.getDate()).padStart(2, "0");
|
||||||
|
const hours = String(d.getHours()).padStart(2, "0");
|
||||||
|
const minutes = String(d.getMinutes()).padStart(2, "0");
|
||||||
|
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCategoryAdd = () => {
|
||||||
|
isEdit.value = false;
|
||||||
|
editId.value = 0;
|
||||||
|
formData.title = "";
|
||||||
|
formData.module_id = null;
|
||||||
|
formData.status = 1;
|
||||||
|
categoryDialogVisible.value = true;
|
||||||
|
fetchModuleOptions();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = (row: Category) => {
|
||||||
|
isEdit.value = true;
|
||||||
|
editId.value = row.id;
|
||||||
|
formData.title = row.title;
|
||||||
|
formData.module_id = row.module_id || null;
|
||||||
|
formData.status = row.status;
|
||||||
|
categoryDialogVisible.value = true;
|
||||||
|
fetchModuleOptions();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleView = (row: Category) => {
|
||||||
|
ElMessage.info("查看分类详情功能开发中");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = (row: Category) => {
|
||||||
|
ElMessageBox.confirm(`确定要删除分类"${row.title}"吗?`, "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(async () => {
|
||||||
|
try {
|
||||||
|
// TODO: 调用删除接口
|
||||||
|
// await deleteCategory(row.id);
|
||||||
|
|
||||||
|
ElMessage.success("删除成功");
|
||||||
|
handleRefresh();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("删除失败:", error);
|
||||||
|
ElMessage.error("删除失败");
|
||||||
|
}
|
||||||
|
}).catch(() => {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCategoryClose = () => {
|
||||||
|
formRef.value?.resetFields();
|
||||||
|
isEdit.value = false;
|
||||||
|
editId.value = 0;
|
||||||
|
categoryDialogVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!formRef.value) return;
|
||||||
|
|
||||||
|
await formRef.value.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
submitLoading.value = true;
|
||||||
|
try {
|
||||||
|
const data = {
|
||||||
|
title: formData.title,
|
||||||
|
status: formData.status
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isEdit.value) {
|
||||||
|
data.id = editId.value;
|
||||||
|
await editModuleCategory(data);
|
||||||
|
ElMessage.success("编辑成功");
|
||||||
|
} else {
|
||||||
|
await editModuleCategory(data);
|
||||||
|
ElMessage.success("添加成功");
|
||||||
|
}
|
||||||
|
handleCategoryClose();
|
||||||
|
handleRefresh();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(isEdit.value ? "编辑失败:" : "添加失败:", error);
|
||||||
|
ElMessage.error(isEdit.value ? "编辑失败" : "添加失败");
|
||||||
|
} finally {
|
||||||
|
submitLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRefresh = () => {
|
||||||
|
fetchCategoryList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchCategoryList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const res = await getModuleCategory();
|
||||||
|
if (res.code === 200 && res.data) {
|
||||||
|
categoryList.value = res.data.list || [];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("获取分类列表失败:", error);
|
||||||
|
ElMessage.error("获取分类列表失败");
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchModuleOptions = async () => {
|
||||||
|
try {
|
||||||
|
// TODO: 调用获取模块列表接口
|
||||||
|
// const res = await getModules(0);
|
||||||
|
// if (res.code === 200) {
|
||||||
|
// moduleOptions.value = res.data.list.map((item: any) => ({
|
||||||
|
// id: item.id,
|
||||||
|
// name: item.title
|
||||||
|
// }));
|
||||||
|
// }
|
||||||
|
moduleOptions.value = [
|
||||||
|
{ id: 1, name: "CMS内容管理" },
|
||||||
|
{ id: 2, name: "用户管理" },
|
||||||
|
{ id: 3, name: "数据分析" },
|
||||||
|
{ id: 4, name: "系统设置" }
|
||||||
|
];
|
||||||
|
} catch (error) {
|
||||||
|
console.error("获取模块列表失败:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchCategoryList();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.category-container {
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
padding: 40px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -3,50 +3,43 @@
|
|||||||
<div class="header-section">
|
<div class="header-section">
|
||||||
<div class="header-top">
|
<div class="header-top">
|
||||||
<div class="category-tabs">
|
<div class="category-tabs">
|
||||||
<div
|
<div v-for="category in categories" :key="category.id" class="category-item"
|
||||||
v-for="category in categories"
|
:class="{ active: activeCategory === category.id }" @click="handleCategoryChange(category.id)">
|
||||||
:key="category.id"
|
{{ category.title }}
|
||||||
class="category-item"
|
|
||||||
:class="{ active: activeCategory === category.id }"
|
|
||||||
@click="handleCategoryChange(category.id)"
|
|
||||||
>
|
|
||||||
{{ category.name }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-loading="loading" class="modules-grid">
|
<div v-loading="loading" class="modules-grid">
|
||||||
<div
|
<div v-for="module in moduleList" :key="module.id" class="module-card" :class="{ disabled: module.status === 0 }">
|
||||||
v-for="module in moduleList"
|
|
||||||
:key="module.id"
|
|
||||||
class="module-card"
|
|
||||||
:class="{ disabled: module.status === 0 }"
|
|
||||||
>
|
|
||||||
<div class="module-preview">
|
<div class="module-preview">
|
||||||
<div class="preview-image">
|
<img v-if="module.thumb" :src="getEnvUrl(module.thumb)" :alt="module.title" />
|
||||||
<el-icon :class="module.icon" :size="40" />
|
<div v-else class="placeholder"></div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="module-content">
|
<div class="module-content">
|
||||||
<h3 class="module-name">{{ module.name }}</h3>
|
<h3 class="module-name">{{ module.title }}</h3>
|
||||||
<p class="module-desc">{{ module.description || '暂无描述' }}</p>
|
<p class="module-desc">{{ module.desc || '暂无描述' }}</p>
|
||||||
<div class="module-footer">
|
<div class="module-footer">
|
||||||
<div class="module-company">
|
<div class="module-category">
|
||||||
<el-icon><OfficeBuilding /></el-icon>
|
<el-icon>
|
||||||
<span>{{ module.code }}</span>
|
<OfficeBuilding />
|
||||||
|
</el-icon>
|
||||||
|
<span>{{ module.cid || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="module-downloads">
|
<div class="module-downloads">
|
||||||
<el-icon><Download /></el-icon>
|
<el-icon>
|
||||||
<span>{{ module.sort }} 次</span>
|
<Download />
|
||||||
|
</el-icon>
|
||||||
|
<span>{{ module.downloads }} 次</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="module-actions">
|
<div class="module-actions">
|
||||||
<el-dropdown trigger="click" @command="(cmd) => handleCommand(cmd, module)">
|
<el-dropdown trigger="click" @command="(cmd) => handleCommand(cmd, module)">
|
||||||
<el-button type="primary" link :icon="MoreFilled" circle />
|
<el-button type="primary" link :icon="MoreFilled" circle class="action-item" />
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item command="edit" :icon="Edit">编辑</el-dropdown-item>
|
<el-dropdown-item command="edit" :icon="Edit">编辑</el-dropdown-item>
|
||||||
@ -65,80 +58,65 @@
|
|||||||
<el-empty description="暂无模块数据" :image-size="120" />
|
<el-empty description="暂无模块数据" :image-size="120" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<create-modules
|
<create-modules v-model="createDialogVisible" @success="handleRefresh" />
|
||||||
v-model="createDialogVisible"
|
|
||||||
@success="handleRefresh"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<el-dialog
|
<el-dialog v-model="editDialogVisible" title="编辑模块" width="600px" :close-on-click-modal="false"
|
||||||
v-model="editDialogVisible"
|
@close="handleEditClose">
|
||||||
title="编辑模块"
|
<el-form ref="editFormRef" :model="editFormData" :rules="formRules" label-width="100px">
|
||||||
width="600px"
|
<el-form-item label="模块名称" prop="title">
|
||||||
:close-on-click-modal="false"
|
<el-input v-model="editFormData.title" placeholder="请输入模块名称" clearable />
|
||||||
@close="handleEditClose"
|
|
||||||
>
|
|
||||||
<el-form
|
|
||||||
ref="editFormRef"
|
|
||||||
:model="editFormData"
|
|
||||||
:rules="formRules"
|
|
||||||
label-width="100px"
|
|
||||||
>
|
|
||||||
<el-form-item label="模块名称" prop="name">
|
|
||||||
<el-input
|
|
||||||
v-model="editFormData.name"
|
|
||||||
placeholder="请输入模块名称"
|
|
||||||
clearable
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="模块代码" prop="code">
|
<el-form-item label="模块描述" prop="desc">
|
||||||
<el-input
|
<el-input v-model="editFormData.desc" type="textarea" :rows="3" placeholder="请输入模块描述" />
|
||||||
v-model="editFormData.code"
|
|
||||||
placeholder="请输入模块代码"
|
|
||||||
clearable
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="模块图标" prop="icon">
|
<el-form-item label="缩略图" prop="thumb">
|
||||||
<el-input
|
<div class="uploads">
|
||||||
v-model="editFormData.icon"
|
<el-upload v-model:file-list="fileList" :auto-upload="false" list-type="picture-card"
|
||||||
placeholder="请输入图标类名,如: fa-solid fa-home"
|
:limit="1" :before-upload="beforeImgUpload" :on-change="handleUploadChange">
|
||||||
clearable
|
<el-icon>
|
||||||
>
|
<Plus />
|
||||||
<template #prefix>
|
</el-icon>
|
||||||
<el-icon v-if="editFormData.icon" :class="editFormData.icon" />
|
|
||||||
|
<template #file="{ file }">
|
||||||
|
<div>
|
||||||
|
<img class="el-upload-list__item-thumbnail" :src="getEnvUrl(file.url)" alt="" />
|
||||||
|
<span class="el-upload-list__item-actions">
|
||||||
|
<span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
|
||||||
|
<el-icon>
|
||||||
|
<ZoomIn />
|
||||||
|
</el-icon>
|
||||||
|
</span>
|
||||||
|
<span class="el-upload-list__item-delete" @click="handleRemove(file)">
|
||||||
|
<el-icon>
|
||||||
|
<Delete />
|
||||||
|
</el-icon>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-upload>
|
||||||
|
<el-dialog v-model="dialogVisible">
|
||||||
|
<img w-full :src="dialogImageUrl" alt="Preview Image" />
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<div class="upload-tip">
|
||||||
|
<span>建议尺寸:250px × 140px</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="模块描述" prop="description">
|
|
||||||
<el-input
|
|
||||||
v-model="editFormData.description"
|
|
||||||
type="textarea"
|
|
||||||
:rows="3"
|
|
||||||
placeholder="请输入模块描述"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="模块类型" prop="type">
|
<el-form-item label="所属分类" prop="cid">
|
||||||
<el-select
|
<el-select v-model="editFormData.cid" placeholder="请选择所属分类">
|
||||||
v-model="editFormData.type"
|
<el-option v-for="cat in categories.filter(c => c.id > 0)" :key="cat.id" :label="cat.title"
|
||||||
placeholder="请选择模块类型"
|
:value="cat.id" />
|
||||||
>
|
|
||||||
<el-option label="前端模块" :value="1" />
|
|
||||||
<el-option label="后端模块" :value="2" />
|
|
||||||
<el-option label="全栈模块" :value="3" />
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="排序" prop="sort">
|
<el-form-item label="版本号" prop="version">
|
||||||
<el-input-number
|
<el-input v-model="editFormData.version" placeholder="请输入版本号,如: 1.0.0" clearable />
|
||||||
v-model="editFormData.sort"
|
|
||||||
:min="0"
|
|
||||||
:max="999"
|
|
||||||
controls-position="right"
|
|
||||||
placeholder="请输入排序"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="状态" prop="status">
|
<el-form-item label="状态" prop="status">
|
||||||
@ -162,21 +140,23 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted } from "vue";
|
import { ref, reactive, onMounted } from "vue";
|
||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
import { ElMessage, ElMessageBox, ElUpload } from "element-plus";
|
||||||
import { Plus, Edit, Delete, Sort, Clock, MoreFilled, OfficeBuilding, Download } from "@element-plus/icons-vue";
|
import { Plus, Edit, Delete, MoreFilled, OfficeBuilding, Download, ZoomIn } from "@element-plus/icons-vue";
|
||||||
import type { FormInstance, FormRules } from "element-plus";
|
import type { FormInstance, FormRules } from "element-plus";
|
||||||
|
import { getModules, getModuleCategory,editModules } from "@/api/moduleCenter";
|
||||||
import CreateModules from "../components/createModules.vue";
|
import CreateModules from "../components/createModules.vue";
|
||||||
|
import { uploadFile } from '@/api/file.js';
|
||||||
|
|
||||||
interface Module {
|
interface Module {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
title: string;
|
||||||
code: string;
|
desc: string;
|
||||||
icon: string;
|
thumb: string;
|
||||||
description: string;
|
cid: number;
|
||||||
type: number;
|
downloads: number;
|
||||||
sort: number;
|
|
||||||
status: number;
|
status: number;
|
||||||
created_at: string;
|
version: string;
|
||||||
|
create_time: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
@ -185,20 +165,16 @@ const createDialogVisible = ref(false);
|
|||||||
const editDialogVisible = ref(false);
|
const editDialogVisible = ref(false);
|
||||||
const editLoading = ref(false);
|
const editLoading = ref(false);
|
||||||
const activeCategory = ref(0);
|
const activeCategory = ref(0);
|
||||||
|
const isEdit = ref(false);
|
||||||
|
const editId = ref<number>(0);
|
||||||
|
|
||||||
// 分类数据
|
// 分类数据
|
||||||
const categories = ref([
|
const categories = ref([
|
||||||
{ id: 0, name: "全部" },
|
{ id: 0, title: "全部" }
|
||||||
{ id: 1, name: "内容管理" },
|
|
||||||
{ id: 2, name: "用户管理" },
|
|
||||||
{ id: 3, name: "数据分析" },
|
|
||||||
{ id: 4, name: "系统工具" },
|
|
||||||
{ id: 5, name: "营销推广" }
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleCategoryChange = (categoryId: number) => {
|
const handleCategoryChange = (categoryId: number) => {
|
||||||
activeCategory.value = categoryId;
|
activeCategory.value = categoryId;
|
||||||
// TODO: 根据分类筛选模块
|
|
||||||
fetchModuleList(categoryId);
|
fetchModuleList(categoryId);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -206,48 +182,89 @@ const editFormRef = ref<FormInstance>();
|
|||||||
|
|
||||||
const editFormData = reactive({
|
const editFormData = reactive({
|
||||||
id: 0,
|
id: 0,
|
||||||
name: "",
|
title: "",
|
||||||
code: "",
|
desc: "",
|
||||||
icon: "",
|
thumb: "",
|
||||||
description: "",
|
cid: 0,
|
||||||
type: 3,
|
downloads: 0,
|
||||||
sort: 0,
|
version: "",
|
||||||
status: 1
|
status: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
const formRules: FormRules = {
|
const formRules: FormRules = {
|
||||||
name: [
|
title: [
|
||||||
{ required: true, message: "请输入模块名称", trigger: "blur" }
|
{ required: true, message: "请输入模块名称", trigger: "blur" }
|
||||||
],
|
],
|
||||||
code: [
|
cid: [
|
||||||
{ required: true, message: "请输入模块代码", trigger: "blur" },
|
{ required: true, message: "请选择分类", trigger: "change" }
|
||||||
{ pattern: /^[a-zA-Z][a-zA-Z0-9]*$/, message: "代码必须以字母开头,只能包含字母和数字", trigger: "blur" }
|
|
||||||
],
|
|
||||||
type: [
|
|
||||||
{ required: true, message: "请选择模块类型", trigger: "change" }
|
|
||||||
],
|
],
|
||||||
status: [
|
status: [
|
||||||
{ required: true, message: "请选择状态", trigger: "change" }
|
{ required: true, message: "请选择状态", trigger: "change" }
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTypeText = (type: number) => {
|
//拼接接口路径
|
||||||
const map: Record<number, string> = {
|
const getEnvUrl = (path: string) => {
|
||||||
1: "前端模块",
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
||||||
2: "后端模块",
|
return `${API_BASE_URL}${path}`;
|
||||||
3: "全栈模块"
|
|
||||||
};
|
|
||||||
return map[type] || "未知";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTypeTagType = (type: number) => {
|
//获取模块分类
|
||||||
const map: Record<number, any> = {
|
async function getModuleCategoryList() {
|
||||||
1: "",
|
try {
|
||||||
2: "warning",
|
const res = await getModuleCategory();
|
||||||
3: "success"
|
if (res.code === 200 && res.data) {
|
||||||
};
|
categories.value = [
|
||||||
return map[type] || "info";
|
{ id: 0, title: "全部" },
|
||||||
};
|
...res.data.list || []
|
||||||
|
];
|
||||||
|
// console.log("分类数据:", categories.value);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("获取分类失败:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传相关
|
||||||
|
const fileList = ref<any[]>([]);
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const dialogImageUrl = ref('');
|
||||||
|
|
||||||
|
function beforeImgUpload(file: File) {
|
||||||
|
const isImage = file.type.startsWith('image/');
|
||||||
|
const isLt10M = file.size / 1024 / 1024 < 10;
|
||||||
|
if (!isImage) ElMessage.error('仅支持图片格式');
|
||||||
|
if (!isLt10M) ElMessage.error('图片大小不能超过10MB');
|
||||||
|
return isImage && isLt10M;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRemove(file: any) {
|
||||||
|
fileList.value = [];
|
||||||
|
editFormData.thumb = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleUploadChange(file: any) {
|
||||||
|
if (file.raw) {
|
||||||
|
const isImage = file.raw.type.startsWith('image/');
|
||||||
|
const isLt10M = file.raw.size / 1024 / 1024 < 10;
|
||||||
|
if (!isImage || !isLt10M) {
|
||||||
|
fileList.value = [];
|
||||||
|
ElMessage.error(isImage ? '图片大小不能超过10MB' : '仅支持图片格式');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePictureCardPreview(file: any) {
|
||||||
|
dialogImageUrl.value = file.url;
|
||||||
|
dialogVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const formatDate = (date: string) => {
|
const formatDate = (date: string) => {
|
||||||
if (!date) return "-";
|
if (!date) return "-";
|
||||||
@ -273,11 +290,25 @@ const handleCommand = (command: string, row: Module) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleEdit = (row: Module) => {
|
const handleEdit = (row: Module) => {
|
||||||
|
isEdit.value = true;
|
||||||
|
editId.value = row.id;
|
||||||
Object.assign(editFormData, row);
|
Object.assign(editFormData, row);
|
||||||
|
// 如果有缩略图,显示在文件列表中
|
||||||
|
if (row.thumb) {
|
||||||
|
fileList.value = [{
|
||||||
|
name: 'thumb',
|
||||||
|
url: row.thumb
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
fileList.value = [];
|
||||||
|
}
|
||||||
editDialogVisible.value = true;
|
editDialogVisible.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditClose = () => {
|
const handleEditClose = () => {
|
||||||
|
isEdit.value = false;
|
||||||
|
editId.value = 0;
|
||||||
|
fileList.value = [];
|
||||||
editFormRef.value?.resetFields();
|
editFormRef.value?.resetFields();
|
||||||
editDialogVisible.value = false;
|
editDialogVisible.value = false;
|
||||||
};
|
};
|
||||||
@ -289,15 +320,43 @@ const handleEditSubmit = async () => {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
editLoading.value = true;
|
editLoading.value = true;
|
||||||
try {
|
try {
|
||||||
// TODO: 调用编辑接口
|
let imageUrl = editFormData.thumb;
|
||||||
// await updateModule(editFormData.id, editFormData);
|
|
||||||
|
|
||||||
|
// 如果有新上传的图片,先上传图片
|
||||||
|
if (fileList.value.length > 0 && fileList.value[0].raw) {
|
||||||
|
const uploadFormData = new FormData();
|
||||||
|
uploadFormData.append('file', fileList.value[0].raw);
|
||||||
|
uploadFormData.append('cate', 'module');
|
||||||
|
|
||||||
|
const uploadRes = await uploadFile(uploadFormData);
|
||||||
|
if (uploadRes?.data?.url) {
|
||||||
|
imageUrl = uploadRes.data.url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
title: editFormData.title,
|
||||||
|
desc: editFormData.desc,
|
||||||
|
thumb: imageUrl,
|
||||||
|
cid: editFormData.cid,
|
||||||
|
downloads: editFormData.downloads,
|
||||||
|
version: editFormData.version,
|
||||||
|
status: editFormData.status
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isEdit.value) {
|
||||||
|
data.id = editId.value;
|
||||||
|
await editModules(data);
|
||||||
ElMessage.success("编辑成功");
|
ElMessage.success("编辑成功");
|
||||||
editDialogVisible.value = false;
|
} else {
|
||||||
|
await editModules(data);
|
||||||
|
ElMessage.success("添加成功");
|
||||||
|
}
|
||||||
|
handleEditClose();
|
||||||
handleRefresh();
|
handleRefresh();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("编辑失败:", error);
|
console.error(isEdit.value ? "编辑失败:" : "添加失败:", error);
|
||||||
ElMessage.error("编辑失败");
|
ElMessage.error(isEdit.value ? "编辑失败" : "添加失败");
|
||||||
} finally {
|
} finally {
|
||||||
editLoading.value = false;
|
editLoading.value = false;
|
||||||
}
|
}
|
||||||
@ -319,7 +378,7 @@ const handleStatusChange = async (row: Module) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = (row: Module) => {
|
const handleDelete = (row: Module) => {
|
||||||
ElMessageBox.confirm(`确定要删除模块"${row.name}"吗?`, "提示", {
|
ElMessageBox.confirm(`确定要删除模块"${row.title}"吗?`, "提示", {
|
||||||
confirmButtonText: "确定",
|
confirmButtonText: "确定",
|
||||||
cancelButtonText: "取消",
|
cancelButtonText: "取消",
|
||||||
type: "warning"
|
type: "warning"
|
||||||
@ -334,7 +393,7 @@ const handleDelete = (row: Module) => {
|
|||||||
console.error("删除失败:", error);
|
console.error("删除失败:", error);
|
||||||
ElMessage.error("删除失败");
|
ElMessage.error("删除失败");
|
||||||
}
|
}
|
||||||
}).catch(() => {});
|
}).catch(() => { });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRefresh = () => {
|
const handleRefresh = () => {
|
||||||
@ -344,93 +403,21 @@ const handleRefresh = () => {
|
|||||||
const fetchModuleList = async (categoryId?: number) => {
|
const fetchModuleList = async (categoryId?: number) => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
// TODO: 调用获取模块列表接口,传入 categoryId 进行筛选
|
// 调用获取模块列表接口
|
||||||
// const res = await getModuleList({ categoryId });
|
const res = await getModules(categoryId || 0);
|
||||||
// if (res.code === 200) {
|
if (res.code === 200 && res.data) {
|
||||||
// moduleList.value = res.data || [];
|
// 转换后端数据格式为前端格式
|
||||||
// }
|
moduleList.value = res.data.list.map((item: any) => ({
|
||||||
|
id: item.id,
|
||||||
// 模拟数据
|
title: item.title,
|
||||||
const allModules = [
|
desc: item.desc,
|
||||||
{
|
thumb: item.thumb,
|
||||||
id: 1,
|
cid: item.cid,
|
||||||
name: "CMS内容管理",
|
downloads: item.downloads,
|
||||||
code: "cms",
|
status: item.status,
|
||||||
icon: "fa-solid fa-newspaper",
|
version: item.version,
|
||||||
description: "内容管理系统模块,支持文章发布、分类管理等功能",
|
create_time: item.create_time
|
||||||
type: 1,
|
}));
|
||||||
sort: 128,
|
|
||||||
status: 1,
|
|
||||||
categoryId: 1,
|
|
||||||
created_at: "2026-01-29 10:00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: "用户管理",
|
|
||||||
code: "user",
|
|
||||||
icon: "fa-solid fa-user",
|
|
||||||
description: "用户管理系统模块,支持用户增删改查、角色权限管理",
|
|
||||||
type: 2,
|
|
||||||
sort: 256,
|
|
||||||
status: 1,
|
|
||||||
categoryId: 2,
|
|
||||||
created_at: "2026-01-29 10:00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: "数据分析",
|
|
||||||
code: "analytics",
|
|
||||||
icon: "fa-solid fa-chart-column",
|
|
||||||
description: "数据分析模块,提供丰富的数据统计和可视化图表",
|
|
||||||
type: 2,
|
|
||||||
sort: 89,
|
|
||||||
status: 1,
|
|
||||||
categoryId: 3,
|
|
||||||
created_at: "2026-01-29 10:00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
name: "系统设置",
|
|
||||||
code: "system",
|
|
||||||
icon: "fa-solid fa-gear",
|
|
||||||
description: "系统配置管理模块,包含站点设置、菜单管理等功能",
|
|
||||||
type: 3,
|
|
||||||
sort: 45,
|
|
||||||
status: 0,
|
|
||||||
categoryId: 4,
|
|
||||||
created_at: "2026-01-29 10:00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
name: "SEO优化",
|
|
||||||
code: "seo",
|
|
||||||
icon: "fa-solid fa-magnifying-glass",
|
|
||||||
description: "搜索引擎优化模块,提升网站排名和流量",
|
|
||||||
type: 1,
|
|
||||||
sort: 67,
|
|
||||||
status: 1,
|
|
||||||
categoryId: 5,
|
|
||||||
created_at: "2026-01-29 10:00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
name: "表单构建器",
|
|
||||||
code: "form-builder",
|
|
||||||
icon: "fa-solid fa-wpforms",
|
|
||||||
description: "可视化表单构建工具,快速创建各类表单",
|
|
||||||
type: 1,
|
|
||||||
sort: 156,
|
|
||||||
status: 1,
|
|
||||||
categoryId: 4,
|
|
||||||
created_at: "2026-01-29 10:00:00"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// 根据分类筛选
|
|
||||||
if (categoryId && categoryId !== 0) {
|
|
||||||
moduleList.value = allModules.filter(m => m.categoryId === categoryId);
|
|
||||||
} else {
|
|
||||||
moduleList.value = allModules;
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("获取模块列表失败:", error);
|
console.error("获取模块列表失败:", error);
|
||||||
@ -442,6 +429,7 @@ const fetchModuleList = async (categoryId?: number) => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchModuleList();
|
fetchModuleList();
|
||||||
|
getModuleCategoryList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -478,7 +466,7 @@ onMounted(() => {
|
|||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--el-text-color-regular);
|
color: var(--el-text-color-regular);
|
||||||
background: var(--el-fill-color-light);
|
background: var(--el-bg-color);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
@ -499,7 +487,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
.modules-grid {
|
.modules-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
grid-template-columns: repeat(5, 1fr);
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
|
|
||||||
.module-card {
|
.module-card {
|
||||||
@ -532,6 +520,12 @@ onMounted(() => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
|
img{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -539,24 +533,9 @@ onMounted(() => {
|
|||||||
right: -50%;
|
right: -50%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: linear-gradient(135deg, rgba(255,255,255,0.3) 0%, transparent 100%);
|
background: linear-gradient(135deg, rgba(255, 255, 255, 0.3) 0%, transparent 100%);
|
||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-image {
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
border-radius: 16px;
|
|
||||||
background: #fff;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
.el-icon {
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-content {
|
.module-content {
|
||||||
@ -589,7 +568,7 @@ onMounted(() => {
|
|||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
border-top: 1px solid var(--el-border-color-lighter);
|
border-top: 1px solid var(--el-border-color-lighter);
|
||||||
|
|
||||||
.module-company,
|
.module-category,
|
||||||
.module-downloads {
|
.module-downloads {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -612,6 +591,11 @@ onMounted(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|
||||||
|
.action-item {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.el-button {
|
.el-button {
|
||||||
color: var(--el-text-color-regular);
|
color: var(--el-text-color-regular);
|
||||||
background: rgba(255, 255, 255, 0.9);
|
background: rgba(255, 255, 255, 0.9);
|
||||||
@ -634,14 +618,63 @@ onMounted(() => {
|
|||||||
padding: 80px 20px;
|
padding: 80px 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.uploads {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-tip {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 1400px) {
|
||||||
.modules-container {
|
.modules-container {
|
||||||
.modules-grid {
|
.modules-grid {
|
||||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
grid-template-columns: repeat(4, 1fr);
|
||||||
gap: 16px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.modules-container {
|
||||||
|
.modules-grid {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.modules-container {
|
||||||
|
.modules-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 576px) {
|
||||||
|
.modules-container {
|
||||||
|
.modules-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.uploads{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.upload-tip {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-upload-list__item-thumbnail) {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span>发布管理</span>
|
<span>发布管理</span>
|
||||||
<el-button type="primary" :icon="Plus" @click="handlePublish">
|
<el-button type="primary" :icon="Plus" @click="handlePublish">
|
||||||
新增发布
|
新增模块
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -17,16 +17,9 @@
|
|||||||
border
|
border
|
||||||
>
|
>
|
||||||
<el-table-column prop="id" label="ID" width="80" />
|
<el-table-column prop="id" label="ID" width="80" />
|
||||||
<el-table-column prop="title" label="发布标题" min-width="200" show-overflow-tooltip />
|
<el-table-column prop="title" label="模块标题" min-width="200" show-overflow-tooltip />
|
||||||
<el-table-column prop="version" label="版本号" width="120" />
|
<el-table-column prop="version" label="版本号" width="120" />
|
||||||
<el-table-column prop="module_name" label="所属模块" width="150" />
|
<el-table-column prop="module_name" label="所属分类" width="150" />
|
||||||
<el-table-column prop="type" label="发布类型" width="100">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<el-tag :type="getTypeTagType(row.type)">
|
|
||||||
{{ getTypeText(row.type) }}
|
|
||||||
</el-tag>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="status" label="状态" width="100">
|
<el-table-column prop="status" label="状态" width="100">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag :type="getStatusType(row.status)">
|
<el-tag :type="getStatusType(row.status)">
|
||||||
@ -34,6 +27,7 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column prop="author" label="作者" width="120" />
|
||||||
<el-table-column prop="publish_time" label="发布时间" width="180">
|
<el-table-column prop="publish_time" label="发布时间" width="180">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ formatDate(row.publish_time) }}
|
{{ formatDate(row.publish_time) }}
|
||||||
@ -70,7 +64,7 @@
|
|||||||
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="publishDialogVisible"
|
v-model="publishDialogVisible"
|
||||||
title="新增发布"
|
title="新增模块"
|
||||||
width="700px"
|
width="700px"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
@close="handlePublishClose"
|
@close="handlePublishClose"
|
||||||
@ -81,10 +75,10 @@
|
|||||||
:rules="formRules"
|
:rules="formRules"
|
||||||
label-width="120px"
|
label-width="120px"
|
||||||
>
|
>
|
||||||
<el-form-item label="发布标题" prop="title">
|
<el-form-item label="模块标题" prop="title">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.title"
|
v-model="formData.title"
|
||||||
placeholder="请输入发布标题"
|
placeholder="请输入模块标题"
|
||||||
clearable
|
clearable
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -97,10 +91,10 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="所属模块" prop="module_id">
|
<el-form-item label="所属分类" prop="module_id">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="formData.module_id"
|
v-model="formData.module_id"
|
||||||
placeholder="请选择所属模块"
|
placeholder="请选择所属分类"
|
||||||
clearable
|
clearable
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
@ -112,14 +106,6 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="发布类型" prop="type">
|
|
||||||
<el-radio-group v-model="formData.type">
|
|
||||||
<el-radio :value="1">更新</el-radio>
|
|
||||||
<el-radio :value="2">新增</el-radio>
|
|
||||||
<el-radio :value="3">修复</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item label="状态" prop="status">
|
<el-form-item label="状态" prop="status">
|
||||||
<el-radio-group v-model="formData.status">
|
<el-radio-group v-model="formData.status">
|
||||||
<el-radio :value="1">发布</el-radio>
|
<el-radio :value="1">发布</el-radio>
|
||||||
@ -162,12 +148,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="发布说明" prop="description">
|
<el-form-item label="模块说明" prop="description">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.description"
|
v-model="formData.description"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:rows="4"
|
:rows="4"
|
||||||
placeholder="请输入发布说明"
|
placeholder="请输入模块说明"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@ -188,12 +174,14 @@ import { ElMessage, ElMessageBox } from "element-plus";
|
|||||||
import { Plus, View, Delete, UploadFilled, Document } from "@element-plus/icons-vue";
|
import { Plus, View, Delete, UploadFilled, Document } from "@element-plus/icons-vue";
|
||||||
import type { FormInstance, FormRules, UploadFile } from "element-plus";
|
import type { FormInstance, FormRules, UploadFile } from "element-plus";
|
||||||
|
|
||||||
|
import { getModules, getModuleCategory } from "@/api/moduleCenter";
|
||||||
|
|
||||||
interface Publish {
|
interface Publish {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
version: string;
|
version: string;
|
||||||
|
author: string;
|
||||||
module_name: string;
|
module_name: string;
|
||||||
type: number;
|
|
||||||
status: number;
|
status: number;
|
||||||
publish_time: string;
|
publish_time: string;
|
||||||
}
|
}
|
||||||
@ -214,8 +202,8 @@ const uploadRef = ref();
|
|||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
title: "",
|
title: "",
|
||||||
version: "",
|
version: "",
|
||||||
|
author: "",
|
||||||
module_id: null as number | null,
|
module_id: null as number | null,
|
||||||
type: 2,
|
|
||||||
status: 1,
|
status: 1,
|
||||||
description: "",
|
description: "",
|
||||||
packageFile: null as File | null
|
packageFile: null as File | null
|
||||||
@ -225,41 +213,20 @@ const moduleOptions = ref<ModuleOption[]>([]);
|
|||||||
|
|
||||||
const formRules: FormRules = {
|
const formRules: FormRules = {
|
||||||
title: [
|
title: [
|
||||||
{ required: true, message: "请输入发布标题", trigger: "blur" }
|
{ required: true, message: "请输入模块标题", trigger: "blur" }
|
||||||
],
|
],
|
||||||
version: [
|
version: [
|
||||||
{ required: true, message: "请输入版本号", trigger: "blur" },
|
{ required: true, message: "请输入版本号", trigger: "blur" },
|
||||||
{ pattern: /^\d+\.\d+\.\d+$/, message: "版本号格式不正确,如: 1.0.0", trigger: "blur" }
|
{ pattern: /^\d+\.\d+\.\d+$/, message: "版本号格式不正确,如: 1.0.0", trigger: "blur" }
|
||||||
],
|
],
|
||||||
module_id: [
|
module_id: [
|
||||||
{ required: true, message: "请选择所属模块", trigger: "change" }
|
{ required: true, message: "请选择所属分类", trigger: "change" }
|
||||||
],
|
|
||||||
type: [
|
|
||||||
{ required: true, message: "请选择发布类型", trigger: "change" }
|
|
||||||
],
|
],
|
||||||
status: [
|
status: [
|
||||||
{ required: true, message: "请选择状态", trigger: "change" }
|
{ required: true, message: "请选择状态", trigger: "change" }
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTypeText = (type: number) => {
|
|
||||||
const map: Record<number, string> = {
|
|
||||||
1: "更新",
|
|
||||||
2: "新增",
|
|
||||||
3: "修复"
|
|
||||||
};
|
|
||||||
return map[type] || "未知";
|
|
||||||
};
|
|
||||||
|
|
||||||
const getTypeTagType = (type: number) => {
|
|
||||||
const map: Record<number, any> = {
|
|
||||||
1: "warning",
|
|
||||||
2: "success",
|
|
||||||
3: "danger"
|
|
||||||
};
|
|
||||||
return map[type] || "info";
|
|
||||||
};
|
|
||||||
|
|
||||||
const getStatusText = (status: number) => {
|
const getStatusText = (status: number) => {
|
||||||
const map: Record<number, string> = {
|
const map: Record<number, string> = {
|
||||||
0: "草稿",
|
0: "草稿",
|
||||||
@ -295,11 +262,11 @@ const handlePublish = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleView = (row: Publish) => {
|
const handleView = (row: Publish) => {
|
||||||
ElMessage.info("查看发布详情功能开发中");
|
ElMessage.info("查看模块详情功能开发中");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = (row: Publish) => {
|
const handleDelete = (row: Publish) => {
|
||||||
ElMessageBox.confirm(`确定要删除发布"${row.title}"吗?`, "提示", {
|
ElMessageBox.confirm(`确定要删除模块"${row.title}"吗?`, "提示", {
|
||||||
confirmButtonText: "确定",
|
confirmButtonText: "确定",
|
||||||
cancelButtonText: "取消",
|
cancelButtonText: "取消",
|
||||||
type: "warning"
|
type: "warning"
|
||||||
@ -355,18 +322,18 @@ const handleSubmit = async () => {
|
|||||||
await formRef.value.validate(async (valid) => {
|
await formRef.value.validate(async (valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (!formData.packageFile) {
|
if (!formData.packageFile) {
|
||||||
ElMessage.warning("请上传发布包");
|
ElMessage.warning("请上传模块包");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
submitLoading.value = true;
|
submitLoading.value = true;
|
||||||
try {
|
try {
|
||||||
// TODO: 调用发布接口
|
// TODO: 调用模块接口
|
||||||
const formDataObj = new FormData();
|
const formDataObj = new FormData();
|
||||||
formDataObj.append("title", formData.title);
|
formDataObj.append("title", formData.title);
|
||||||
formDataObj.append("version", formData.version);
|
formDataObj.append("version", formData.version);
|
||||||
|
formDataObj.append("author", formData.author);
|
||||||
formDataObj.append("module_id", formData.module_id.toString());
|
formDataObj.append("module_id", formData.module_id.toString());
|
||||||
formDataObj.append("type", formData.type.toString());
|
|
||||||
formDataObj.append("status", formData.status.toString());
|
formDataObj.append("status", formData.status.toString());
|
||||||
formDataObj.append("description", formData.description);
|
formDataObj.append("description", formData.description);
|
||||||
formDataObj.append("package", formData.packageFile);
|
formDataObj.append("package", formData.packageFile);
|
||||||
@ -391,45 +358,21 @@ const handleRefresh = () => {
|
|||||||
const fetchPublishList = async () => {
|
const fetchPublishList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
// TODO: 调用获取发布列表接口
|
const res = await getModules(0);
|
||||||
// const res = await getPublishList();
|
if (res.code === 200 && res.data) {
|
||||||
// if (res.code === 200) {
|
publishList.value = res.data.list.map((item: any) => ({
|
||||||
// publishList.value = res.data || [];
|
id: item.id,
|
||||||
// }
|
title: item.title,
|
||||||
|
version: item.version || "-",
|
||||||
// 模拟数据
|
author: item.author || "-",
|
||||||
publishList.value = [
|
module_name: item.cid || "",
|
||||||
{
|
status: item.status,
|
||||||
id: 1,
|
publish_time: item.create_time || ""
|
||||||
title: "CMS内容管理 v1.0.0",
|
}));
|
||||||
version: "1.0.0",
|
|
||||||
module_name: "CMS内容管理",
|
|
||||||
type: 2,
|
|
||||||
status: 1,
|
|
||||||
publish_time: "2026-01-29 10:00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
title: "用户管理 v1.0.1",
|
|
||||||
version: "1.0.1",
|
|
||||||
module_name: "用户管理",
|
|
||||||
type: 1,
|
|
||||||
status: 1,
|
|
||||||
publish_time: "2026-01-28 10:00:00"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
title: "数据分析 v1.0.0",
|
|
||||||
version: "1.0.0",
|
|
||||||
module_name: "数据分析",
|
|
||||||
type: 3,
|
|
||||||
status: 0,
|
|
||||||
publish_time: "2026-01-27 10:00:00"
|
|
||||||
}
|
}
|
||||||
];
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("获取发布列表失败:", error);
|
console.error("获取模块列表失败:", error);
|
||||||
ElMessage.error("获取发布列表失败");
|
ElMessage.error("获取模块列表失败");
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
@ -437,15 +380,15 @@ const fetchPublishList = async () => {
|
|||||||
|
|
||||||
const fetchModuleOptions = async () => {
|
const fetchModuleOptions = async () => {
|
||||||
try {
|
try {
|
||||||
// TODO: 调用获取模块列表接口
|
const res = await getModuleCategory();
|
||||||
moduleOptions.value = [
|
if (res.code === 200 && res.data) {
|
||||||
{ id: 1, name: "CMS内容管理" },
|
moduleOptions.value = res.data.list.map((item: any) => ({
|
||||||
{ id: 2, name: "用户管理" },
|
id: item.id,
|
||||||
{ id: 3, name: "数据分析" },
|
name: item.title
|
||||||
{ id: 4, name: "系统设置" }
|
}));
|
||||||
];
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("获取模块列表失败:", error);
|
console.error("获取分类列表失败:", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user