From 494e0160b79a22b2e0df71e61d9bb4de333cadbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=AB=E5=9C=B0=E5=83=A7?= <357099073@qq.com> Date: Sun, 2 Nov 2025 13:17:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=A7=9F=E6=88=B7=E5=82=A8?= =?UTF-8?q?=E5=AD=98=E5=AE=B9=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pc/src/components/CommonAside.vue | 2 +- pc/src/router/index.js | 50 - pc/src/views/Main.vue | 167 ++- .../views/apps/knowledge/category/index.vue | 170 +++- .../apps/knowledge/components/detail.vue | 319 +++--- .../views/apps/knowledge/components/edit.vue | 368 +++---- pc/src/views/apps/knowledge/index.vue | 923 ++++++----------- pc/src/views/apps/knowledge/tag/index.vue | 175 ++++ pc/src/views/dashboard/index.vue | 962 +++++++++++------- .../views/system/tenant/components/audit.vue | 227 +++++ .../views/system/tenant/components/detail.vue | 215 ++++ .../views/system/tenant/components/edit.vue | 236 +++++ pc/src/views/system/tenant/index.vue | 738 +++++--------- server/models/tenant.go | 14 +- 14 files changed, 2621 insertions(+), 1945 deletions(-) diff --git a/pc/src/components/CommonAside.vue b/pc/src/components/CommonAside.vue index 75a5155..f0565a2 100644 --- a/pc/src/components/CommonAside.vue +++ b/pc/src/components/CommonAside.vue @@ -362,7 +362,7 @@ const findMenuItemByPath = (menus, path) => { } h3{ - line-height: 60px; + line-height: 80px; display: flex; align-items: center; justify-content: center; diff --git a/pc/src/router/index.js b/pc/src/router/index.js index c79a119..c3969cf 100644 --- a/pc/src/router/index.js +++ b/pc/src/router/index.js @@ -65,28 +65,22 @@ export async function loadAndAddDynamicRoutes() { // 创建加载 Promise routesLoadingPromise = (async () => { try { - console.log('[路由加载] 开始从 API 加载动态路由...'); - // 直接从 API 获取菜单数据 const { getAllMenus } = await import("@/api/menu"); const res = await getAllMenus(); if (res && res.success && res.data) { - console.log('[路由加载] API 返回菜单数量:', res.data.length); // 添加动态路由 addDynamicRoutes(res.data); - console.log('[路由加载] 动态路由加载完成'); dynamicRoutesAdded = true; routesLoadingPromise = null; return Promise.resolve(); } else { - console.warn('[路由加载] API 返回数据格式异常:', res); dynamicRoutesAdded = true; routesLoadingPromise = null; return Promise.resolve(); } } catch (error) { - console.error('[路由加载] 加载动态路由失败:', error); // 即使出错也标记为已加载,避免无限重试 dynamicRoutesAdded = true; routesLoadingPromise = null; @@ -100,15 +94,11 @@ export async function loadAndAddDynamicRoutes() { // 添加动态路由到 Main 的 children 中 function addDynamicRoutes(menus) { if (!menus?.length) { - console.warn('[路由加载] 菜单数据为空,跳过添加动态路由'); return; } - console.log('[路由加载] 开始添加动态路由,菜单数量:', menus.length); - // 如果已经添加过,先移除旧路由(刷新时可能需要重新添加) if (dynamicRoutesAdded) { - console.log('[路由加载] 检测到已添加的路由,先移除旧路由'); // 移除 Main 路由以便重新添加 if (router.hasRoute('Main')) { router.removeRoute('Main'); @@ -120,18 +110,10 @@ function addDynamicRoutes(menus) { const filteredMenus = menus.filter(menu => menu.id !== 1); const dynamicRoutes = convertMenusToRoutes(filteredMenus); - console.log('[路由加载] 转换后的动态路由数量:', dynamicRoutes.length); - console.log('[路由加载] 动态路由列表:', dynamicRoutes.map(r => ({ - path: r.path, - name: r.name, - hasComponent: !!r.component, - childrenCount: r.children?.length || 0 - }))); // 获取主路由 const mainRoute = router.getRoutes().find(r => r.name === 'Main'); if (!mainRoute) { - console.error('[路由加载] 找不到 Main 路由'); return; } @@ -157,7 +139,6 @@ function addDynamicRoutes(menus) { }; router.addRoute(newMainRoute); - console.log('[路由加载] Main 路由已更新,子路由总数:', newMainRoute.children.length); // 添加知识库的子路由(详情页和编辑页) // 直接在 Main 路由下添加完整路径的子路由 @@ -227,22 +208,16 @@ router.beforeEach(async (to, from, next) => { // 3. 已登录,确保动态路由已加载(必须在检查 404 之前) if (!dynamicRoutesAdded) { - console.log('[路由守卫] 开始加载动态路由, 目标路径:', to.path); await loadAndAddDynamicRoutes(); - console.log('[路由守卫] 动态路由加载完成, dynamicRoutesAdded:', dynamicRoutesAdded); - // 如果路由加载后仍然未添加(API 失败) if (!dynamicRoutesAdded) { - console.warn('[路由守卫] 路由加载失败,可能是 API 错误或 token 无效'); // 重新检查 token,如果 token 不存在或无效,跳转到登录页 const currentToken = localStorage.getItem('token'); if (!currentToken) { - console.log('[路由守卫] 未找到 token,跳转到登录页'); next({ path: "/login", query: { redirect: to.path } }); return; } // 如果 token 存在但路由加载失败,可能是 token 过期或无效,清除 token 并跳转登录 - console.warn('[路由守卫] Token 存在但路由加载失败,清除 token 并跳转登录页'); localStorage.removeItem('token'); localStorage.removeItem('userInfo'); next({ path: "/login", query: { redirect: to.path } }); @@ -254,23 +229,14 @@ router.beforeEach(async (to, from, next) => { // 重新解析路径检查是否能匹配 const resolved = router.resolve(to.path); - console.log('[路由守卫] 路由解析结果:', { - path: to.path, - resolved: resolved.path, - matched: resolved.matched.length, - name: resolved.name, - matchedRoutes: resolved.matched.map(m => ({ name: m.name, path: m.path })) - }); // 如果能匹配到路由,使用完整路径重新导航(确保Vue Router正确更新) if (resolved.matched.length > 0 && resolved.name !== "NotFound") { - console.log('[路由守卫] 路由匹配成功,重新导航确保正确加载'); next({ path: to.fullPath || to.path, replace: true }); return; } // 如果无法匹配,使用原始路径重新导航 - console.log('[路由守卫] 路由未匹配,重新导航到:', to.path); next({ path: to.fullPath || to.path, replace: true }); return; } @@ -278,29 +244,13 @@ router.beforeEach(async (to, from, next) => { // 3.5 如果路由已加载但当前路径未匹配,可能是刷新问题 // 注意:这里需要排除根路径和已知的静态路由 if (to.matched.length === 0 && to.name !== "NotFound" && to.path !== "/" && to.path !== "/dashboard") { - console.log('[路由守卫] 路由已加载但未匹配,尝试重新解析:', to.path); // 重新解析路径,看看是否能够匹配 const resolved = router.resolve(to.path); - console.log('[路由守卫] 重新解析结果:', { - matched: resolved.matched.length, - name: resolved.name, - matchedRoutes: resolved.matched.map(m => ({ name: m.name, path: m.path })) - }); if (resolved.matched.length > 0 && resolved.name !== "NotFound") { // 能够匹配,说明路由表正常,使用路径重新导航 - console.log('[路由守卫] 重新解析匹配成功,重新导航'); next({ path: to.path, replace: true }); return; - } else { - console.warn('[路由守卫] 路由确实无法匹配,可能是路径错误:', to.path); - // 打印所有已注册的路由用于调试 - const allRoutes = router.getRoutes(); - console.log('[路由守卫] 所有已注册的路由:', allRoutes.map(r => ({ - name: r.name, - path: r.path, - children: r.children?.map(c => ({ name: c.name, path: c.path })) - }))); } } diff --git a/pc/src/views/Main.vue b/pc/src/views/Main.vue index 1477cca..9e9ef1c 100644 --- a/pc/src/views/Main.vue +++ b/pc/src/views/Main.vue @@ -4,7 +4,7 @@ import CommonHeader from '@/components/CommonHeader.vue'; import { useTabsStore } from '@/stores'; import { useRouter, useRoute } from 'vue-router'; import { ref, watch, reactive, nextTick, onMounted } from 'vue'; -import { More, DArrowRight } from '@element-plus/icons-vue' +import { More, Close, CircleClose } from '@element-plus/icons-vue' const tabsStore = useTabsStore(); const router = useRouter(); @@ -175,16 +175,20 @@ function closeAllTabs() { @contextmenu="onTabContextMenu($event, tab)" /> - -
- - - - + +
+ + + + @@ -220,47 +224,132 @@ function closeAllTabs() { .main-header { background-color: var(--header-bg-color, #0081ff); transition: background-color 0.3s ease; - height: 60px; + height: 80px; padding: 0; } .right-main { - background-color: var(--bg-color-page); - color: var(--text-color-primary); + background-color: var(--el-bg-color-page); + color: var(--el-text-color-primary); transition: background-color 0.3s ease, color 0.3s ease; padding: 20px; overflow-y: auto; - // 注意:overflow-y: auto 不会影响 fixed 定位的元素(fixed 相对于 viewport) + .multi-tabs-wrapper { position: relative; - zoom: 1; - min-height: 45px; - } - .floated-tabs-extra-btn { - float: right; - margin-top: -40px; - margin-right: 12px; - z-index: 10; - } - .extra-action-btn { - display: inline-flex; + display: flex; align-items: center; - font-size: 20px; - cursor: pointer; - color: #888; - background: none; - border: none; - padding: 0 8px; - border-radius: 4px; - transition: color 0.2s; - &:hover { - color: #409eff; - background: none; + gap: 12px; + margin-bottom: 16px; + background: var(--el-bg-color); + border-radius: 8px; + padding: 8px 12px; + border: 1px solid var(--el-border-color-lighter); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); + } + + .multi-tabs { + flex: 1; + min-width: 0; + + :deep(.el-tabs__header) { + margin: 0; + border-bottom: none; + } + + :deep(.el-tabs__nav-wrap) { + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: thin; + scrollbar-color: var(--el-border-color) transparent; + + &::-webkit-scrollbar { + height: 4px; + } + + &::-webkit-scrollbar-track { + background: transparent; + } + + &::-webkit-scrollbar-thumb { + background: var(--el-border-color); + border-radius: 2px; + + &:hover { + background: var(--el-border-color-darker); + } + } + } + + :deep(.el-tabs__item) { + border: 1px solid var(--el-border-color-lighter); + border-radius: 6px; + margin-right: 8px; + padding: 8px 16px; + height: 36px; + line-height: 20px; + color: var(--el-text-color-regular); + background: var(--el-fill-color-lighter); + transition: all 0.3s; + + &:hover { + color: var(--el-color-primary); + border-color: var(--el-color-primary-light-7); + background: var(--el-color-primary-light-9); + } + + &.is-active { + color: var(--el-color-primary); + border-color: #4f84ff; + background: #4f84ff; + color: #fff; + + .el-icon-close { + color: rgba(255, 255, 255, 0.8); + + &:hover { + color: #fff; + background-color: rgba(255, 255, 255, 0.2); + } + } + } + + .el-icon-close { + margin-left: 8px; + border-radius: 50%; + width: 16px; + height: 16px; + line-height: 16px; + transition: all 0.2s; + + &:hover { + background-color: var(--el-fill-color); + } + } + } + + :deep(.el-tabs__nav) { + border: none; + } + + :deep(.el-tabs__content) { + display: none; } } - .more-menu { - font-size: 13px; - margin-left: 10px; - cursor: pointer; + + .tabs-extra-actions { + flex-shrink: 0; + display: flex; + align-items: center; + + .extra-btn { + padding: 8px; + font-size: 18px; + color: var(--el-text-color-regular); + + &:hover { + color: var(--el-color-primary); + } + } } } } diff --git a/pc/src/views/apps/knowledge/category/index.vue b/pc/src/views/apps/knowledge/category/index.vue index 65d7a47..9252099 100644 --- a/pc/src/views/apps/knowledge/category/index.vue +++ b/pc/src/views/apps/knowledge/category/index.vue @@ -1,13 +1,173 @@ - - \ No newline at end of file +.page-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + + .page-title { + margin: 0; + font-size: 20px; + font-weight: 600; + color: var(--el-text-color-primary); + } +} + +.category-content { + :deep(.el-card) { + background: var(--el-bg-color); + border: 1px solid var(--el-border-color-lighter); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); + } +} + diff --git a/pc/src/views/apps/knowledge/components/detail.vue b/pc/src/views/apps/knowledge/components/detail.vue index 2bafd4d..5565891 100644 --- a/pc/src/views/apps/knowledge/components/detail.vue +++ b/pc/src/views/apps/knowledge/components/detail.vue @@ -2,68 +2,76 @@
- 返回 -

{{ knowledgeTitle }}

+ + + 返回 + +

{{ knowledgeTitle }}

+
+ + + 编辑 + + + + 删除 + +
- -
- 基本信息 -
+
+

基本信息

- - - {{ formData.title }} - - - {{ formData.category }} - - - {{ tag }} - - - {{ formData.author }} - - - {{ formData.createTime }} - - - {{ formData.updateTime }} - - - - - 编辑 - 删除 - - +
+
+ 标题: + {{ formData.title }} +
+
+ 分类: + {{ formData.category }} +
+
+ 标签: +
+ + {{ tag }} + +
+
+
+ 作者: + {{ formData.author }} +
+
+ 创建时间: + {{ formData.createTime }} +
+
+ 更新时间: + {{ formData.updateTime }} +
+
+
- -
- 正文内容 -
+
+

正文内容

- +
@@ -73,6 +81,7 @@ import { ref, computed, onMounted } from 'vue' import { useRoute, useRouter } from 'vue-router' import { ElMessage, ElMessageBox } from 'element-plus' +import { ArrowLeft, Edit, Delete } from '@element-plus/icons-vue' import { marked } from "marked" import { getKnowledgeDetail, deleteKnowledge } from "@/api/knowledge" @@ -90,6 +99,7 @@ interface FormData { updateTime: string, content: string, } + const formData = ref({ title: "", category: "", @@ -124,7 +134,6 @@ async function fetchDetail() { try { const idValue = id.value as string | number const res = await getKnowledgeDetail(idValue) - // API 返回的数据结构: { code: 0, data: {...}, message: "success" } const data = (res.code === 0 && res.data) ? res.data : (res.data || res) formData.value = { title: data.title || '', @@ -142,14 +151,17 @@ async function fetchDetail() { ElMessage.error("获取详情失败") } } + onMounted(fetchDetail) function goBack() { router.push("/apps/knowledge") } + function handleEdit() { router.push(`/apps/knowledge/edit/${id.value}`) } + function handleDelete() { ElMessageBox.confirm( "确认删除该知识?", @@ -163,7 +175,6 @@ function handleDelete() { try { const idValue = id.value as string | number const res = await deleteKnowledge(idValue) - // API 返回的数据结构: { code: 0, message: "删除成功", data: null } if (res.code === 0) { ElMessage.success("删除成功") goBack() @@ -178,32 +189,35 @@ function handleDelete() { diff --git a/pc/src/views/apps/knowledge/components/edit.vue b/pc/src/views/apps/knowledge/components/edit.vue index 7e73594..47a241c 100644 --- a/pc/src/views/apps/knowledge/components/edit.vue +++ b/pc/src/views/apps/knowledge/components/edit.vue @@ -2,15 +2,18 @@
- 返回 -

{{ isEdit ? "编辑知识" : "新建知识" }}

+ + + 返回 + +

{{ isEdit ? "编辑知识" : "新建知识" }}

- +
+

基本信息

+ - - - - - - - + + + + + + + - + - + - + - + 个人 共享 @@ -77,35 +80,35 @@ -
- 保存 + + + 保存 + 取消
- +
- - - - +
+

编辑正文

+ +
+ +
+
- - +
+

预览效果

+
- +
@@ -115,18 +118,18 @@ import { ref, reactive, computed, onMounted, watch } from "vue"; import { useRouter, useRoute } from "vue-router"; import { marked } from "marked"; +import { ArrowLeft, Check } from '@element-plus/icons-vue' // @ts-ignore -import { getKnowledgeDetail, createKnowledge, updateKnowledge, getCategoryList, getTagList } from "@/api/knowledge"; // Changed to getKnowledgeDetail +import { getKnowledgeDetail, createKnowledge, updateKnowledge, getCategoryList, getTagList } from "@/api/knowledge"; import { ElMessage, ElMessageBox } from "element-plus"; import type { FormInstance, FormRules } from "element-plus"; +import WangEditor from '@/views/components/WangEditor.vue'; -// 表单 DOM 引用 const formRef = ref(); const router = useRouter(); const route = useRoute(); -// 表单数据 const formData = reactive<{ title: string; category: string; @@ -145,7 +148,6 @@ const formData = reactive<{ share: 0, }); -// 校验规则 const rules = reactive({ title: [{ required: true, message: "请输入标题", trigger: "blur" }], category: [{ required: true, message: "请选择分类", trigger: "change" }], @@ -153,7 +155,6 @@ const rules = reactive({ content: [{ required: true, message: "请输入正文", trigger: "blur" }], }); -// 分类与标签数据 interface CategoryItem { categoryId: number; categoryName: string; @@ -161,18 +162,14 @@ interface CategoryItem { const categoryList = ref([]); const tagList = ref([]); -// id: 编辑时有,新增为 'new' const id = computed(() => route.params.id || route.query.id); const isEdit = computed(() => { const currentId = id.value; return !!currentId && currentId !== "new" && currentId !== ""; }); -// markdown 预览 const compiledMarkdown = computed(() => marked(formData.content || "")); -// TODO: 后续可以集成 wangEditor -// 暂时使用 textarea,监听内容变化 watch( () => formData.content, () => { @@ -180,7 +177,6 @@ watch( } ); -// 获取登录用户信息 const getLoginUser = () => { const userStr = localStorage.getItem("user"); if (userStr) { @@ -194,25 +190,20 @@ const getLoginUser = () => { return ""; }; -// 获取详情 const fetchDetail = async () => { try { const currentId = id.value as string; if (currentId && currentId !== "new") { - const res = await getKnowledgeDetail(parseInt(currentId as string)); // Changed to getKnowledgeDetail - // API 返回的数据结构: { code: 0, data: {...}, message: "success" } + const res = await getKnowledgeDetail(parseInt(currentId as string)); const data = res.code === 0 && res.data ? res.data : res.data || res; - // 映射后端数据到前端表单 - // categoryName 是从数据库联查得到的分类名称 formData.title = data.title || ""; formData.category = data.categoryName || ""; formData.categoryId = data.categoryId || 0; formData.author = data.author || ""; formData.content = data.content || ""; - formData.share = data.share || 0; // Added share loading + formData.share = data.share || 0; - // 如果没有 categoryId,尝试根据 categoryName 查找 if (!formData.categoryId && formData.category) { const foundCategory = categoryList.value.find( (item) => item.categoryName === formData.category @@ -222,14 +213,12 @@ const fetchDetail = async () => { } } - // Tags 可能是 JSON 字符串,需要解析 if (data.tags) { try { const parsed = typeof data.tags === "string" ? JSON.parse(data.tags) : data.tags; formData.tags = Array.isArray(parsed) ? parsed : []; } catch { - // 如果解析失败,尝试作为字符串数组处理 formData.tags = Array.isArray(data.tags) ? data.tags : []; } } else { @@ -241,7 +230,6 @@ const fetchDetail = async () => { } }; -// 获取分类和标签 const loadCategoryAndTag = async () => { try { const [catRes, tagRes] = await Promise.all([ @@ -249,14 +237,12 @@ const loadCategoryAndTag = async () => { getTagList(), ]); - // API 返回的数据结构: { code: 0, data: [...], message: "success" } const categories = catRes.code === 0 && catRes.data ? catRes.data : catRes.data || []; const tags = tagRes.code === 0 && tagRes.data ? tagRes.data : tagRes.data || []; categoryList.value = Array.isArray(categories) ? categories : []; - // 标签数据可能是 { tagId, tagName } 格式,需要提取 tagName tagList.value = Array.isArray(tags) ? tags.map((tag) => tag.tagName || tag) : []; @@ -267,7 +253,6 @@ const loadCategoryAndTag = async () => { } }; -// 处理分类变化 const handleCategoryChange = (categoryName: string) => { const selectedCategory = categoryList.value.find( (item) => item.categoryName === categoryName @@ -277,12 +262,10 @@ const handleCategoryChange = (categoryName: string) => { } }; -// 返回 const goBack = () => { router.push("/apps/knowledge"); }; -// 保存 const handleSubmit = () => { if (!formRef.value) return; formRef.value.validate(async (valid: boolean) => { @@ -290,14 +273,11 @@ const handleSubmit = () => { const currentId = id.value as string; - // 检查 categoryId 是否已设置 if (!formData.categoryId) { ElMessage.warning("请选择分类"); return; } - // 准备提交的数据(符合后端格式,字段名对应后端 JSON tag) - // 确保数据类型正确:categoryId 必须是数字 const submitData: any = { title: formData.title || "", categoryId: Number(formData.categoryId) || 0, @@ -307,21 +287,18 @@ const handleSubmit = () => { Array.isArray(formData.tags) && formData.tags.length > 0 ? JSON.stringify(formData.tags) : "[]", - status: 1, // 默认已发布 - share: formData.share, // Added share in params + status: 1, + share: formData.share, }; if (isEdit.value && currentId !== "new") { - // 编辑:需要添加 id(后端 JSON tag 是 "id") const knowledgeId = parseInt(currentId as string); if (isNaN(knowledgeId) || knowledgeId <= 0) { ElMessage.error("知识ID无效"); return; } - // updateKnowledge 函数会将 id 合并到 data 中,所以这里不需要手动添加 try { const res = await updateKnowledge(knowledgeId, submitData); - // API 返回的数据结构: { code: 0, message: "更新成功", data: null } if (res.code === 0) { ElMessage.success("保存成功"); goBack(); @@ -335,10 +312,8 @@ const handleSubmit = () => { ElMessage.error(errorMessage); } } else { - // 新建:不包含 id 字段 try { const res = await createKnowledge(submitData); - // API 返回的数据结构: { code: 0, message: "创建成功", data: { id: ... } } if (res.code === 0) { ElMessage.success("创建成功"); goBack(); @@ -355,41 +330,17 @@ const handleSubmit = () => { }); }; -//删除功能 -const handleDelete = async () => { - try { - // Assuming deleteKnowledge is imported or defined elsewhere - // await deleteKnowledge(id.value as string); - ElMessage.success("删除成功"); - goBack(); - } catch (e: any) { - console.error("删除失败:", e); - } - ElMessageBox.confirm("确认删除该知识?", "提示", { - confirmButtonText: "确定", - cancelButtonText: "取消", - type: "warning", - }).then(async () => { - await handleDelete(); - }); -}; - -// 初始化 onMounted(async () => { - // 获取作者信息 const author = getLoginUser(); if (author && !isEdit.value) { formData.author = author; } - // 先加载分类和标签 await loadCategoryAndTag(); - // 如果是编辑模式,获取详情 if (isEdit.value) { await fetchDetail(); } else { - // 如果是新建模式,设置默认分类 if (categoryList.value.length > 0 && !formData.category) { formData.category = categoryList.value[0].categoryName; formData.categoryId = categoryList.value[0].categoryId; @@ -397,7 +348,6 @@ onMounted(async () => { } }); -// 暴露到模板 defineExpose({ formRef, }); @@ -405,165 +355,123 @@ defineExpose({ diff --git a/pc/src/views/apps/knowledge/index.vue b/pc/src/views/apps/knowledge/index.vue index 94c3363..785bef2 100644 --- a/pc/src/views/apps/knowledge/index.vue +++ b/pc/src/views/apps/knowledge/index.vue @@ -1,32 +1,31 @@ @@ -266,6 +275,7 @@ import { ref, reactive, computed, onMounted } from "vue"; import { useRouter } from "vue-router"; import { ElMessage, ElMessageBox } from "element-plus"; +import { Search, Plus, Folder, PriceTag, User, View, Star, Clock } from "@element-plus/icons-vue"; // @ts-ignore import { getKnowledgeList, deleteKnowledge } from "@/api/knowledge"; @@ -481,661 +491,346 @@ onMounted(() => { diff --git a/pc/src/views/apps/knowledge/tag/index.vue b/pc/src/views/apps/knowledge/tag/index.vue index e69de29..3a2e79a 100644 --- a/pc/src/views/apps/knowledge/tag/index.vue +++ b/pc/src/views/apps/knowledge/tag/index.vue @@ -0,0 +1,175 @@ + + + + + + diff --git a/pc/src/views/dashboard/index.vue b/pc/src/views/dashboard/index.vue index 5738dfb..eff0a47 100644 --- a/pc/src/views/dashboard/index.vue +++ b/pc/src/views/dashboard/index.vue @@ -1,89 +1,236 @@ diff --git a/pc/src/views/system/tenant/components/audit.vue b/pc/src/views/system/tenant/components/audit.vue index e69de29..3e50315 100644 --- a/pc/src/views/system/tenant/components/audit.vue +++ b/pc/src/views/system/tenant/components/audit.vue @@ -0,0 +1,227 @@ + + + + + + diff --git a/pc/src/views/system/tenant/components/detail.vue b/pc/src/views/system/tenant/components/detail.vue index e69de29..e346204 100644 --- a/pc/src/views/system/tenant/components/detail.vue +++ b/pc/src/views/system/tenant/components/detail.vue @@ -0,0 +1,215 @@ + + + + + + diff --git a/pc/src/views/system/tenant/components/edit.vue b/pc/src/views/system/tenant/components/edit.vue index e69de29..8dc82a9 100644 --- a/pc/src/views/system/tenant/components/edit.vue +++ b/pc/src/views/system/tenant/components/edit.vue @@ -0,0 +1,236 @@ + + + + + + diff --git a/pc/src/views/system/tenant/index.vue b/pc/src/views/system/tenant/index.vue index 2accfee..fa16da2 100644 --- a/pc/src/views/system/tenant/index.vue +++ b/pc/src/views/system/tenant/index.vue @@ -1,96 +1,117 @@ + diff --git a/server/models/tenant.go b/server/models/tenant.go index 4fa8d34..67137e7 100644 --- a/server/models/tenant.go +++ b/server/models/tenant.go @@ -14,11 +14,13 @@ type Tenant struct { Owner string `orm:"size(50)" json:"owner"` Phone string `orm:"size(20);null" json:"phone"` Email string `orm:"size(100);null" json:"email"` - Status string `orm:"size(20);default(enabled)" json:"status"` // enabled, disabled - AuditStatus string `orm:"size(20);default(pending)" json:"audit_status"` // pending, approved, rejected + Status string `orm:"size(20);default(enabled)" json:"status"` + AuditStatus string `orm:"size(20);default(pending)" json:"audit_status"` AuditComment string `orm:"type(text);null" json:"audit_comment"` AuditBy string `orm:"size(50);null" json:"audit_by"` AuditTime *time.Time `orm:"null;type(datetime)" json:"audit_time"` + Capacity int `orm:"default(0)" json:"capacity"` + CapacityUsed int `orm:"default(0)" json:"capacity_used"` Remark string `orm:"type(text);null" json:"remark"` CreateTime time.Time `orm:"auto_now_add;type(datetime)" json:"create_time"` UpdateTime time.Time `orm:"auto_now;type(datetime)" json:"update_time"` @@ -69,7 +71,7 @@ func UpdateTenant(id int, data map[string]interface{}) error { return err } -// DeleteTenant 软删除租户(设置 delete_time) +// DeleteTenant 软删除租户 func DeleteTenant(id int) error { o := orm.NewOrm() deleteTime := time.Now() @@ -77,7 +79,7 @@ func DeleteTenant(id int) error { return err } -// AuditTenant 审核租户(只能审核未删除的) +// AuditTenant 审核租户 func AuditTenant(id int, auditStatus, auditComment, auditBy string) error { o := orm.NewOrm() tenant := Tenant{} @@ -99,7 +101,7 @@ func AuditTenant(id int, auditStatus, auditComment, auditBy string) error { return err } -// GetTenantById 根据ID获取租户详情(只返回未删除的) +// GetTenantById 根据ID获取租户详情 func GetTenantById(id int) (*Tenant, error) { o := orm.NewOrm() tenant := Tenant{} @@ -111,7 +113,7 @@ func GetTenantById(id int) (*Tenant, error) { return &tenant, err } -// GetTenantByName 根据名称获取租户详情(只返回未删除的) +// GetTenantByName 根据名称获取租户详情 func GetTenantByName(name string) (*Tenant, error) { o := orm.NewOrm() tenant := Tenant{}