优化backend产品和解决方案
This commit is contained in:
@@ -296,6 +296,14 @@ const fixedCmsMenu = {
|
|||||||
icon: "Document",
|
icon: "Document",
|
||||||
order: -200,
|
order: -200,
|
||||||
children: [
|
children: [
|
||||||
|
{
|
||||||
|
id: -2001,
|
||||||
|
path: "/apps/cms/analytics/content",
|
||||||
|
title: "内容统计",
|
||||||
|
icon: "DataAnalysis",
|
||||||
|
order: 0,
|
||||||
|
children: []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: -201,
|
id: -201,
|
||||||
path: "/apps/cms/article",
|
path: "/apps/cms/article",
|
||||||
|
|||||||
@@ -160,11 +160,13 @@ export function convertMenusToRoutes(menus, parentPath = '') {
|
|||||||
} else if (hasChildren) {
|
} else if (hasChildren) {
|
||||||
route.component = () => import('@/views/layouts/EmptyLayout.vue');
|
route.component = () => import('@/views/layouts/EmptyLayout.vue');
|
||||||
route.children = convertMenusToRoutes(menu.children, fullPath);
|
route.children = convertMenusToRoutes(menu.children, fullPath);
|
||||||
const firstChild = menu.children[0];
|
const defaultChild = menu.children.find((child) =>
|
||||||
if (firstChild && firstChild.path) {
|
child.path === '/apps/cms/analytics/content' || child.path === 'analytics/content'
|
||||||
const childFullPath = firstChild.path.startsWith('/')
|
) || menu.children[0];
|
||||||
? firstChild.path
|
if (defaultChild && defaultChild.path) {
|
||||||
: `${fullPath}/${firstChild.path}`;
|
const childFullPath = defaultChild.path.startsWith('/')
|
||||||
|
? defaultChild.path
|
||||||
|
: `${fullPath}/${defaultChild.path}`;
|
||||||
route.redirect = childFullPath;
|
route.redirect = childFullPath;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ const staticMainChildren = [
|
|||||||
},
|
},
|
||||||
// CMS 文章/产品/解决方案是系统内置功能,不依赖数据库菜单配置。
|
// CMS 文章/产品/解决方案是系统内置功能,不依赖数据库菜单配置。
|
||||||
// 统一结构:index 为列表页,type 为分类页。
|
// 统一结构:index 为列表页,type 为分类页。
|
||||||
|
{
|
||||||
|
path: "/apps/cms/analytics/content",
|
||||||
|
name: "CmsContentAnalytics",
|
||||||
|
component: () => import("@/views/apps/cms/analytics/content/index.vue"),
|
||||||
|
meta: { requiresAuth: true, title: "内容统计", modulePath: "/apps/cms" }
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/apps/cms/article",
|
path: "/apps/cms/article",
|
||||||
name: "CmsArticles",
|
name: "CmsArticles",
|
||||||
|
|||||||
@@ -98,6 +98,20 @@ const getCategoryName = (cate) => {
|
|||||||
return category?.name || "无分类";
|
return category?.name || "无分类";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 格式化日期
|
||||||
|
const formatDate = (date: string | number | Date) => {
|
||||||
|
if (!date) return "-";
|
||||||
|
const d = new Date(date);
|
||||||
|
if (isNaN(d.getTime())) return String(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");
|
||||||
|
const seconds = String(d.getSeconds()).padStart(2, "0");
|
||||||
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||||
|
};
|
||||||
|
|
||||||
const emit = defineEmits(["update:modelValue"]);
|
const emit = defineEmits(["update:modelValue"]);
|
||||||
|
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
|
|||||||
@@ -213,8 +213,8 @@
|
|||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
import { Search } from "@element-plus/icons-vue";
|
import { Search } from "@element-plus/icons-vue";
|
||||||
import Edit from "./index/components/edit.vue";
|
import Edit from "./components/edit.vue";
|
||||||
import Preview from "./index/components/preview.vue";
|
import Preview from "./components/preview.vue";
|
||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
import {
|
import {
|
||||||
listArticles,
|
listArticles,
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog
|
<el-drawer
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
:title="title"
|
:title="title"
|
||||||
width="600px"
|
size="65%"
|
||||||
|
class="cms-product-drawer"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
@close="handleClose"
|
@close="handleClose"
|
||||||
>
|
>
|
||||||
@@ -11,6 +12,7 @@
|
|||||||
:model="formData"
|
:model="formData"
|
||||||
:rules="formRules"
|
:rules="formRules"
|
||||||
label-width="100px"
|
label-width="100px"
|
||||||
|
class="product-form"
|
||||||
>
|
>
|
||||||
<el-form-item label="产品名称" prop="title">
|
<el-form-item label="产品名称" prop="title">
|
||||||
<el-input v-model="formData.title" placeholder="请输入产品名称" />
|
<el-input v-model="formData.title" placeholder="请输入产品名称" />
|
||||||
@@ -19,11 +21,11 @@
|
|||||||
<el-input
|
<el-input
|
||||||
v-model="formData.desc"
|
v-model="formData.desc"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:rows="5"
|
:rows="4"
|
||||||
placeholder="请输入产品描述"
|
placeholder="请输入产品描述"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="产品内容" prop="content">
|
<el-form-item label="产品内容" prop="content" class="content-form-item">
|
||||||
<div class="editor-container">
|
<div class="editor-container">
|
||||||
<UmoEditor v-model="formData.content" style="height: 450px;" />
|
<UmoEditor v-model="formData.content" style="height: 450px;" />
|
||||||
</div>
|
</div>
|
||||||
@@ -87,7 +89,7 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -265,6 +267,30 @@ const handleSubmit = async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
:deep(.el-drawer__body) {
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-form {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-form-item__content) {
|
||||||
|
min-width: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
border: 1px solid var(--el-border-color, #dcdfe6);
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
.dialog-footer {
|
.dialog-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog
|
<el-drawer
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
:title="title"
|
:title="title"
|
||||||
width="600px"
|
size="65%"
|
||||||
|
class="cms-solution-drawer"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
@close="handleClose"
|
@close="handleClose"
|
||||||
>
|
>
|
||||||
@@ -11,19 +12,25 @@
|
|||||||
:model="formData"
|
:model="formData"
|
||||||
:rules="formRules"
|
:rules="formRules"
|
||||||
label-width="100px"
|
label-width="100px"
|
||||||
|
class="solution-form"
|
||||||
>
|
>
|
||||||
<el-form-item label="服务名称" prop="title">
|
<el-form-item label="方案名称" prop="title">
|
||||||
<el-input v-model="formData.title" placeholder="请输入服务名称" />
|
<el-input v-model="formData.title" placeholder="请输入解决方案名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="服务描述" prop="desc">
|
<el-form-item label="方案描述" prop="desc">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.desc"
|
v-model="formData.desc"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:rows="5"
|
:rows="4"
|
||||||
placeholder="请输入服务描述"
|
placeholder="请输入解决方案描述"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Logo" prop="thumb">
|
<el-form-item label="方案内容" prop="content" class="content-form-item">
|
||||||
|
<div class="editor-container">
|
||||||
|
<UmoEditor v-model="formData.content" style="height: 450px;" />
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="方案图片" prop="thumb">
|
||||||
<div class="flex-direction">
|
<div class="flex-direction">
|
||||||
<el-upload
|
<el-upload
|
||||||
class="image-uploader"
|
class="image-uploader"
|
||||||
@@ -42,7 +49,7 @@
|
|||||||
/>
|
/>
|
||||||
<div v-else class="upload-placeholder">
|
<div v-else class="upload-placeholder">
|
||||||
<el-icon class="image-uploader-icon"><Plus /></el-icon>
|
<el-icon class="image-uploader-icon"><Plus /></el-icon>
|
||||||
<div class="el-upload__text">点击上传服务图标</div>
|
<div class="el-upload__text">点击上传方案图片</div>
|
||||||
</div>
|
</div>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<div
|
<div
|
||||||
@@ -63,7 +70,7 @@
|
|||||||
@click="handleRemoveImage"
|
@click="handleRemoveImage"
|
||||||
style="margin-top: 8px"
|
style="margin-top: 8px"
|
||||||
>
|
>
|
||||||
删除图标
|
删除图片
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="排序" prop="sort">
|
<el-form-item label="排序" prop="sort">
|
||||||
@@ -82,7 +89,7 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -101,7 +108,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "添加服务",
|
default: "添加解决方案",
|
||||||
},
|
},
|
||||||
isEdit: {
|
isEdit: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -144,7 +151,7 @@ const beforeImageUpload = (file) => {
|
|||||||
// 图片上传成功
|
// 图片上传成功
|
||||||
const handleImageSuccess = (response) => {
|
const handleImageSuccess = (response) => {
|
||||||
if (response.code === 200 || response.code === 201) {
|
if (response.code === 200 || response.code === 201) {
|
||||||
formData.link_logo = response.data.url || response.data.path;
|
formData.thumb = response.data.url || response.data.path;
|
||||||
ElMessage.success(
|
ElMessage.success(
|
||||||
response.code === 201 ? "文件已存在,直接使用" : "图片上传成功",
|
response.code === 201 ? "文件已存在,直接使用" : "图片上传成功",
|
||||||
);
|
);
|
||||||
@@ -160,7 +167,7 @@ const handleImageError = () => {
|
|||||||
|
|
||||||
// 删除图片
|
// 删除图片
|
||||||
const handleRemoveImage = () => {
|
const handleRemoveImage = () => {
|
||||||
formData.link_logo = "";
|
formData.thumb = "";
|
||||||
ElMessage.success("图片已删除");
|
ElMessage.success("图片已删除");
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -174,6 +181,7 @@ const getImageUrl = (imagePath) => {
|
|||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
title: "",
|
title: "",
|
||||||
desc: "",
|
desc: "",
|
||||||
|
content: "",
|
||||||
thumb: "",
|
thumb: "",
|
||||||
url: "",
|
url: "",
|
||||||
sort: 0,
|
sort: 0,
|
||||||
@@ -182,11 +190,11 @@ const formData = reactive({
|
|||||||
|
|
||||||
const formRules = {
|
const formRules = {
|
||||||
title: [
|
title: [
|
||||||
{ required: true, message: "请输入服务名称", trigger: "blur" },
|
{ required: true, message: "请输入解决方案名称", trigger: "blur" },
|
||||||
{ max: 100, message: "长度不超过100个字符", trigger: "blur" },
|
{ max: 100, message: "长度不超过100个字符", trigger: "blur" },
|
||||||
],
|
],
|
||||||
desc: [
|
desc: [
|
||||||
{ required: true, message: "请输入服务描述", trigger: "blur" },
|
{ required: true, message: "请输入解决方案描述", trigger: "blur" },
|
||||||
{ max: 200, message: "描述长度不超过200个字符", trigger: "blur" },
|
{ max: 200, message: "描述长度不超过200个字符", trigger: "blur" },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@@ -214,6 +222,7 @@ watch(visible, (val) => {
|
|||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
formData.title = "";
|
formData.title = "";
|
||||||
formData.desc = "";
|
formData.desc = "";
|
||||||
|
formData.content = "";
|
||||||
formData.thumb = "";
|
formData.thumb = "";
|
||||||
formData.url = "";
|
formData.url = "";
|
||||||
formData.sort = 0;
|
formData.sort = 0;
|
||||||
@@ -259,6 +268,30 @@ const handleSubmit = async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
:deep(.el-drawer__body) {
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.solution-form {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-form-item__content) {
|
||||||
|
min-width: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
border: 1px solid var(--el-border-color, #dcdfe6);
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
.dialog-footer {
|
.dialog-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container-box">
|
<div class="container-box">
|
||||||
<div class="header-bar">
|
<div class="header-bar">
|
||||||
<h2>特色服务管理</h2>
|
<h2>解决方案管理</h2>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<el-button type="primary" @click="handleTypes">
|
<el-button type="primary" @click="handleTypes">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
<el-icon>
|
<el-icon>
|
||||||
<Plus />
|
<Plus />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
添加内容
|
添加解决方案
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="refresh" :loading="loading">
|
<el-button @click="refresh" :loading="loading">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
<!-- 搜索栏 -->
|
<!-- 搜索栏 -->
|
||||||
<div class="search-bar">
|
<div class="search-bar">
|
||||||
<el-input v-model="searchForm.keyword" placeholder="请输入内容搜索" clearable style="width: 200px; margin-right: 10px"
|
<el-input v-model="searchForm.keyword" placeholder="请输入解决方案名称搜索" clearable style="width: 200px; margin-right: 10px"
|
||||||
@keyup.enter="handleSearch" />
|
@keyup.enter="handleSearch" />
|
||||||
<el-select v-model="searchForm.status" placeholder="状态筛选" clearable style="width: 120px; margin-right: 10px">
|
<el-select v-model="searchForm.status" placeholder="状态筛选" clearable style="width: 120px; margin-right: 10px">
|
||||||
<el-option label="启用" :value="1" />
|
<el-option label="启用" :value="1" />
|
||||||
@@ -46,9 +46,23 @@
|
|||||||
<!-- 数据表格 -->
|
<!-- 数据表格 -->
|
||||||
<el-table :data="servicesList" style="width: 100%" v-loading="loading" @selection-change="handleSelectionChange">
|
<el-table :data="servicesList" style="width: 100%" v-loading="loading" @selection-change="handleSelectionChange">
|
||||||
<el-table-column prop="id" label="ID" width="80" align="center" />
|
<el-table-column prop="id" label="ID" width="80" align="center" />
|
||||||
<el-table-column prop="thumb" label="服务图片" min-width="150" align="center" />
|
<el-table-column prop="thumb" label="方案图片" min-width="150" align="center">
|
||||||
<el-table-column prop="title" label="服务名称" min-width="150" align="center" />
|
<template #default="{ row }">
|
||||||
<el-table-column prop="desc" label="服务描述" min-width="150" align="center" />
|
<el-image v-if="row.thumb" :src="getImageUrl(row.thumb)" :preview-src-list="[getImageUrl(row.thumb)]"
|
||||||
|
fit="cover" class="solution-thumb" :preview-teleported="true" lazy>
|
||||||
|
<template #error>
|
||||||
|
<div class="image-slot">
|
||||||
|
<el-icon>
|
||||||
|
<Picture />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
<span v-else class="text-gray">暂无图片</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="title" label="方案名称" min-width="150" align="center" />
|
||||||
|
<el-table-column prop="desc" label="方案描述" min-width="150" align="center" />
|
||||||
<el-table-column prop="url" label="跳转地址" min-width="150" align="center" />
|
<el-table-column prop="url" label="跳转地址" min-width="150" align="center" />
|
||||||
<el-table-column prop="sort" label="排序" width="80" align="center" />
|
<el-table-column prop="sort" label="排序" width="80" align="center" />
|
||||||
<el-table-column prop="create_time" label="创建时间" width="180" align="center" />
|
<el-table-column prop="create_time" label="创建时间" width="180" align="center" />
|
||||||
@@ -148,8 +162,8 @@ const fetchList = async () => {
|
|||||||
pagination.total = res.data.total
|
pagination.total = res.data.total
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取特色服务列表失败:', error)
|
console.error('获取解决方案列表失败:', error)
|
||||||
ElMessage.error('获取特色服务列表失败')
|
ElMessage.error('获取解决方案列表失败')
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
@@ -193,7 +207,7 @@ const handleSelectionChange = (selection) => {
|
|||||||
// 添加
|
// 添加
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
isEdit.value = false
|
isEdit.value = false
|
||||||
dialogTitle.value = '添加特色服务'
|
dialogTitle.value = '添加解决方案'
|
||||||
currentRow.value = {}
|
currentRow.value = {}
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
@@ -201,7 +215,7 @@ const handleAdd = () => {
|
|||||||
// 编辑
|
// 编辑
|
||||||
const handleEdit = (row) => {
|
const handleEdit = (row) => {
|
||||||
isEdit.value = true
|
isEdit.value = true
|
||||||
dialogTitle.value = '编辑特色服务'
|
dialogTitle.value = '编辑解决方案'
|
||||||
currentRow.value = row
|
currentRow.value = row
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
@@ -209,7 +223,7 @@ const handleEdit = (row) => {
|
|||||||
// 删除
|
// 删除
|
||||||
const handleDelete = async (row) => {
|
const handleDelete = async (row) => {
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm('确定要删除该特色服务吗?', '提示', {
|
await ElMessageBox.confirm('确定要删除该解决方案吗?', '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
@@ -224,8 +238,8 @@ const handleDelete = async (row) => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error !== 'cancel') {
|
if (error !== 'cancel') {
|
||||||
console.error('删除特色服务失败:', error)
|
console.error('删除解决方案失败:', error)
|
||||||
ElMessage.error('删除特色服务失败')
|
ElMessage.error('删除解决方案失败')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,8 +255,8 @@ const handleStatusChange = async (row, val) => {
|
|||||||
row.status = val === 1 ? 0 : 1
|
row.status = val === 1 ? 0 : 1
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('更新特色服务状态失败:', error)
|
console.error('更新解决方案状态失败:', error)
|
||||||
ElMessage.error('更新特色服务状态失败')
|
ElMessage.error('更新解决方案状态失败')
|
||||||
row.status = val === 1 ? 0 : 1
|
row.status = val === 1 ? 0 : 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<umo-editor
|
<div class="umo-editor-wrapper">
|
||||||
ref="editorRef"
|
<umo-editor
|
||||||
v-bind="options"
|
ref="editorRef"
|
||||||
@changed="onChanged"
|
v-bind="options"
|
||||||
@created="onCreated"
|
@changed="onChanged"
|
||||||
@file-upload="onFileUpload"
|
@created="onCreated"
|
||||||
/>
|
@file-upload="onFileUpload"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -64,3 +66,20 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.umo-editor-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
:deep(.umo-editor),
|
||||||
|
:deep(umo-editor) {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
v-for="module in basicModules"
|
v-for="module in basicModules"
|
||||||
:key="module.path"
|
:key="module.path"
|
||||||
class="module-card"
|
class="module-card"
|
||||||
@click="handleNavigate(module.path)"
|
@click="handleNavigate(module)"
|
||||||
>
|
>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span class="card-title">{{ module.name }}</span>
|
<span class="card-title">{{ module.name }}</span>
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
v-for="module in systemModules"
|
v-for="module in systemModules"
|
||||||
:key="module.path"
|
:key="module.path"
|
||||||
class="module-card"
|
class="module-card"
|
||||||
@click="handleNavigate(module.path)"
|
@click="handleNavigate(module)"
|
||||||
>
|
>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span class="card-title">{{ module.name }}</span>
|
<span class="card-title">{{ module.name }}</span>
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
v-for="module in uncategorizedModules"
|
v-for="module in uncategorizedModules"
|
||||||
:key="module.path"
|
:key="module.path"
|
||||||
class="module-card"
|
class="module-card"
|
||||||
@click="handleNavigate(module.path)"
|
@click="handleNavigate(module)"
|
||||||
>
|
>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span class="card-title">{{ module.name }}</span>
|
<span class="card-title">{{ module.name }}</span>
|
||||||
@@ -222,8 +222,13 @@ const userName = computed(
|
|||||||
const userAvatar = computed(() => authStore.user?.avatar || "");
|
const userAvatar = computed(() => authStore.user?.avatar || "");
|
||||||
|
|
||||||
// 处理导航跳转
|
// 处理导航跳转
|
||||||
function handleNavigate(path: string) {
|
function handleNavigate(module: ModuleItem) {
|
||||||
if (path) router.push(path);
|
const isWebsiteManagement = module.name === "网站管理" || module.path.startsWith("/apps/cms");
|
||||||
|
const targetPath = isWebsiteManagement
|
||||||
|
? "/apps/cms/analytics/content"
|
||||||
|
: module.path;
|
||||||
|
|
||||||
|
if (targetPath) router.push(targetPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 刷新菜单
|
// 刷新菜单
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ func cmsSolutionToMap(row models.CmsSolution) map[string]interface{} {
|
|||||||
"title": row.Title,
|
"title": row.Title,
|
||||||
"thumb": row.Thumb,
|
"thumb": row.Thumb,
|
||||||
"desc": row.Desc,
|
"desc": row.Desc,
|
||||||
|
"content": row.Content,
|
||||||
"url": row.URL,
|
"url": row.URL,
|
||||||
"sort": row.Sort,
|
"sort": row.Sort,
|
||||||
"status": row.Status,
|
"status": row.Status,
|
||||||
@@ -141,12 +142,13 @@ func (c *BackendSolutionController) List() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type cmsSolutionPayload struct {
|
type cmsSolutionPayload struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Thumb string `json:"thumb"`
|
Thumb string `json:"thumb"`
|
||||||
Desc string `json:"desc"`
|
Desc string `json:"desc"`
|
||||||
URL string `json:"url"`
|
Content string `json:"content"`
|
||||||
Sort int `json:"sort"`
|
URL string `json:"url"`
|
||||||
Status int8 `json:"status"`
|
Sort int `json:"sort"`
|
||||||
|
Status int8 `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create POST /backend/addServices
|
// Create POST /backend/addServices
|
||||||
@@ -187,6 +189,7 @@ func (c *BackendSolutionController) Create() {
|
|||||||
Title: title,
|
Title: title,
|
||||||
Thumb: strings.TrimSpace(p.Thumb),
|
Thumb: strings.TrimSpace(p.Thumb),
|
||||||
Desc: strings.TrimSpace(p.Desc),
|
Desc: strings.TrimSpace(p.Desc),
|
||||||
|
Content: p.Content,
|
||||||
URL: strings.TrimSpace(p.URL),
|
URL: strings.TrimSpace(p.URL),
|
||||||
Sort: p.Sort,
|
Sort: p.Sort,
|
||||||
Status: p.Status,
|
Status: p.Status,
|
||||||
@@ -245,6 +248,7 @@ func (c *BackendSolutionController) Update() {
|
|||||||
"title": title,
|
"title": title,
|
||||||
"thumb": strings.TrimSpace(p.Thumb),
|
"thumb": strings.TrimSpace(p.Thumb),
|
||||||
"desc": strings.TrimSpace(p.Desc),
|
"desc": strings.TrimSpace(p.Desc),
|
||||||
|
"content": p.Content,
|
||||||
"url": strings.TrimSpace(p.URL),
|
"url": strings.TrimSpace(p.URL),
|
||||||
"sort": p.Sort,
|
"sort": p.Sort,
|
||||||
"status": p.Status,
|
"status": p.Status,
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/beego/beego/v2/client/orm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type BackendMenuFront struct {
|
type BackendMenuFront struct {
|
||||||
@@ -27,7 +25,3 @@ type BackendMenuFront struct {
|
|||||||
func (m *BackendMenuFront) TableName() string {
|
func (m *BackendMenuFront) TableName() string {
|
||||||
return "yz_backend_menu_front"
|
return "yz_backend_menu_front"
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
orm.RegisterModel(new(BackendMenuFront))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ type CmsSolution struct {
|
|||||||
Title string `orm:"column(title);size(100)" json:"title"`
|
Title string `orm:"column(title);size(100)" json:"title"`
|
||||||
Thumb string `orm:"column(thumb);size(500);default()" json:"thumb"`
|
Thumb string `orm:"column(thumb);size(500);default()" json:"thumb"`
|
||||||
Desc string `orm:"column(desc);size(500);default()" json:"desc"`
|
Desc string `orm:"column(desc);size(500);default()" json:"desc"`
|
||||||
|
Content string `orm:"column(content);type(mediumtext);null" json:"content"`
|
||||||
URL string `orm:"column(url);size(500);default()" json:"url"`
|
URL string `orm:"column(url);size(500);default()" json:"url"`
|
||||||
Sort int `orm:"column(sort);default(0)" json:"sort"`
|
Sort int `orm:"column(sort);default(0)" json:"sort"`
|
||||||
Status int8 `orm:"column(status);default(1)" json:"status"`
|
Status int8 `orm:"column(status);default(1)" json:"status"`
|
||||||
@@ -55,6 +56,7 @@ CREATE TABLE IF NOT EXISTS yz_cms_solution (
|
|||||||
title varchar(100) NOT NULL DEFAULT '',
|
title varchar(100) NOT NULL DEFAULT '',
|
||||||
thumb varchar(500) NOT NULL DEFAULT '',
|
thumb varchar(500) NOT NULL DEFAULT '',
|
||||||
` + "`desc`" + ` varchar(500) NOT NULL DEFAULT '',
|
` + "`desc`" + ` varchar(500) NOT NULL DEFAULT '',
|
||||||
|
content mediumtext,
|
||||||
url varchar(500) NOT NULL DEFAULT '',
|
url varchar(500) NOT NULL DEFAULT '',
|
||||||
sort int NOT NULL DEFAULT 0,
|
sort int NOT NULL DEFAULT 0,
|
||||||
status tinyint NOT NULL DEFAULT 1,
|
status tinyint NOT NULL DEFAULT 1,
|
||||||
@@ -67,6 +69,8 @@ CREATE TABLE IF NOT EXISTS yz_cms_solution (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 确保已有表补齐 content 字段
|
||||||
|
_, _ = Orm.Raw("ALTER TABLE yz_cms_solution ADD COLUMN content mediumtext").Exec()
|
||||||
_, err = Orm.Raw(`
|
_, err = Orm.Raw(`
|
||||||
CREATE TABLE IF NOT EXISTS yz_cms_solution_category (
|
CREATE TABLE IF NOT EXISTS yz_cms_solution_category (
|
||||||
id bigint unsigned NOT NULL AUTO_INCREMENT,
|
id bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
|||||||
@@ -69,11 +69,16 @@ func Init(_ string) {
|
|||||||
|
|
||||||
new(CmsArticleCategory),
|
new(CmsArticleCategory),
|
||||||
new(CmsArticle),
|
new(CmsArticle),
|
||||||
|
new(CmsProductCategory),
|
||||||
|
new(CmsProduct),
|
||||||
|
new(CmsSolutionCategory),
|
||||||
|
new(CmsSolution),
|
||||||
|
|
||||||
new(CmsFrontendTemplate),
|
new(CmsFrontendTemplate),
|
||||||
new(CmsFrontendBanner),
|
new(CmsFrontendBanner),
|
||||||
new(CmsFrontendFriendlink),
|
new(CmsFrontendFriendlink),
|
||||||
new(CmsFrontendOnepage),
|
new(CmsFrontendOnepage),
|
||||||
|
new(BackendMenuFront),
|
||||||
|
|
||||||
new(SystemReminderList),
|
new(SystemReminderList),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user