fix(faq): repair category schema and icons

This commit is contained in:
Cheng Zhou
2026-06-08 13:38:09 +08:00
parent 30e2398400
commit d472b8410e
8 changed files with 115 additions and 26 deletions
+1 -2
View File
@@ -5,7 +5,6 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="data:," />
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
<title>CTMS</title>
</head>
@@ -14,4 +13,4 @@
<script type="module" src="/src/main.ts"></script>
</body>
</html>
</html>
+2 -1
View File
@@ -41,7 +41,7 @@
'icon-option--used': isIconUsedByOther(icon.cls),
}]"
@click="selectIcon(icon.cls)"
><i :class="['fas', icon.cls]"></i></span>
><FaqIcon :icon="icon.cls" /></span>
</div>
</el-form-item>
</div>
@@ -62,6 +62,7 @@
<script setup lang="ts">
import { computed, reactive, ref, watch } from "vue";
import { ElMessage, ElMessageBox, FormInstance, FormRules } from "element-plus";
import FaqIcon from "./FaqIcon.vue";
import { createFaqCategory, updateFaqCategory, deleteFaqCategory } from "../api/faqs";
import { useStudyStore } from "../store/study";
import { TEXT, requiredMessage } from "../locales";
@@ -14,7 +14,7 @@
<div class="editor-title-row">
<div class="editor-title">分类管理</div>
<el-button size="small" class="header-add-btn" @click="addCategory">
<i class="fas fa-plus"></i> 新增
<el-icon><Plus /></el-icon> 新增
</el-button>
</div>
</div>
@@ -32,10 +32,10 @@
<span class="sort-num">{{ idx + 1 }}</span>
<div class="sort-arrows">
<button class="sort-btn" :disabled="idx === 0" @click="moveUp(idx)" title="上移">
<i class="fas fa-chevron-up"></i>
<el-icon><ArrowUp /></el-icon>
</button>
<button class="sort-btn" :disabled="idx === editableCategories.length - 1" @click="moveDown(idx)" title="下移">
<i class="fas fa-chevron-down"></i>
<el-icon><ArrowDown /></el-icon>
</button>
</div>
</div>
@@ -48,8 +48,8 @@
>
<template #reference>
<div class="row-icon" :class="{ 'row-icon--selected': cat.icon }" title="选择图标">
<i v-if="cat.icon" :class="['fas', cat.icon]"></i>
<span v-else class="row-icon-placeholder"><i class="fas fa-icons"></i></span>
<FaqIcon v-if="cat.icon" :icon="cat.icon" />
<span v-else class="row-icon-placeholder"><Grid /></span>
</div>
</template>
<div class="icon-popover-grid">
@@ -59,7 +59,7 @@
:title="icon.label"
:class="['mini-icon', { 'mini-icon--active': cat.icon === icon.cls }]"
@click="selectIconFor(cat, icon.cls)"
><i :class="['fas', icon.cls]"></i></span>
><FaqIcon :icon="icon.cls" /></span>
</div>
</el-popover>
@@ -77,7 +77,7 @@
class="row-delete"
type="button"
@click.stop="removeCategory(cat)"
><i class="fas fa-trash"></i></button>
><el-icon><Delete /></el-icon></button>
</div>
</div>
</div>
@@ -96,6 +96,8 @@
<script setup lang="ts">
import { computed, ref, watch } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { ArrowDown, ArrowUp, Delete, Grid, Plus } from "@element-plus/icons-vue";
import FaqIcon from "./FaqIcon.vue";
import { createFaqCategory, updateFaqCategory, deleteFaqCategory } from "../api/faqs";
import type { FaqCategory } from "../api/faqs";
import { useStudyStore } from "../store/study";
+6 -14
View File
@@ -8,13 +8,13 @@
</div>
<el-menu :default-active="activeCategory" @select="onSelect" class="menu">
<el-menu-item index="">
<span class="cat-icon"><i class="fas fa-th-large"></i></span>
<span class="cat-icon"><FaqIcon icon="fa-th-large" /></span>
<span class="name">{{ TEXT.common.labels.all }}</span>
<span class="cat-count">{{ totalFaqCount }}</span>
</el-menu-item>
<el-menu-item v-for="c in sortedCategories" :key="c.id" :index="c.id">
<span class="cat-icon">
<i v-if="c.icon" :class="['fas', c.icon]"></i>
<FaqIcon v-if="c.icon" :icon="c.icon" />
<span v-else>{{ c.name.slice(0, 1) }}</span>
</span>
<span class="name" :title="c.name">{{ c.name }}</span>
@@ -27,10 +27,9 @@
<script setup lang="ts">
import { computed, ref } from "vue";
import FaqIcon from "./FaqIcon.vue";
import FaqCategoryManager from "./FaqCategoryManager.vue";
import type { FaqCategory } from "../api/faqs";
import { useAuthStore } from "../store/auth";
import { useStudyStore } from "../store/study";
import { usePermission } from "../utils/permission";
import { TEXT } from "../locales";
@@ -41,13 +40,9 @@ const props = defineProps<{
}>();
const emit = defineEmits(["update:modelValue", "refresh"]);
const auth = useAuthStore();
const study = useStudyStore();
const showForm = ref(false);
const { can } = usePermission();
const isAdmin = computed(() => !!auth.user?.is_admin);
const canCreateCategory = computed(() => can("faq.category.create"));
const sortedCategories = computed(() =>
[...props.categories].sort((a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0))
@@ -75,11 +70,6 @@ const onSelect = (id: string) => {
emit("update:modelValue", id);
};
const activeIcons = (excludeId?: string) =>
sortedCategories.value
.filter((c) => c.id !== excludeId && c.icon)
.map((c) => c.icon as string);
const openManager = () => {
showForm.value = true;
};
@@ -146,8 +136,10 @@ const openManager = () => {
font-size: 13px;
font-weight: 800;
}
.cat-icon i {
.cat-icon :deep(svg) {
font-size: 13px;
width: 1em;
height: 1em;
}
.menu :deep(.el-menu-item.is-active) .cat-icon {
background: #d7ebff;
+58
View File
@@ -0,0 +1,58 @@
<template>
<component :is="iconComponent" />
</template>
<script setup lang="ts">
import { computed } from "vue";
import type { Component } from "vue";
import {
Calendar,
Camera,
Collection,
DocumentChecked,
Filter,
FirstAidKit,
Flag,
Grid,
Help,
List,
Management,
Memo,
More,
OfficeBuilding,
Reading,
ScaleToOriginal,
Sell,
SetUp,
User,
} from "@element-plus/icons-vue";
const props = defineProps<{
icon?: string | null;
}>();
const iconMap: Record<string, Component> = {
"fa-th-large": Grid,
"fa-ruler-combined": ScaleToOriginal,
"fa-calendar-check": Calendar,
"fa-filter": Filter,
"fa-flag-checkered": Flag,
"fa-capsules": FirstAidKit,
"fa-prescription-bottle": Sell,
"fa-vial": SetUp,
"fa-heartbeat": Help,
"fa-pills": FirstAidKit,
"fa-file-medical": DocumentChecked,
"fa-camera": Camera,
"fa-notes-medical": Memo,
"fa-clipboard-list": List,
"fa-syringe": FirstAidKit,
"fa-flask": Management,
"fa-book-medical": Reading,
"fa-user-md": User,
"fa-hospital": OfficeBuilding,
"fa-ellipsis-h": More,
};
const iconComponent = computed(() => iconMap[props.icon || ""] || Collection);
</script>
+2 -2
View File
@@ -2,7 +2,7 @@
<div class="page ctms-page-shell page--flush medical-consult-page">
<div class="page-bg-dots"></div>
<section class="faq-hero">
<h1><i class="fas fa-book-medical hero-title-icon"></i>项目知识库</h1>
<h1><el-icon class="hero-title-icon"><Collection /></el-icon>项目知识库</h1>
<div class="hero-tools">
<el-autocomplete
v-model="keyword"
@@ -74,7 +74,7 @@
<script setup lang="ts">
import { computed, onMounted, ref, watch } from "vue";
import { ElMessage } from "element-plus";
import { Plus, Search } from "@element-plus/icons-vue";
import { Collection, Plus, Search } from "@element-plus/icons-vue";
import { fetchFaqCategories, fetchFaqItems } from "../api/faqs";
import FaqCategoryPanel from "../components/FaqCategoryPanel.vue";
import FaqList from "../components/FaqList.vue";