180 lines
4.8 KiB
Vue
180 lines
4.8 KiB
Vue
<template>
|
|
<div class="page ctms-page-shell page--flush">
|
|
<el-row :gutter="12">
|
|
<el-col :span="5">
|
|
<FaqCategoryPanel
|
|
v-model="activeCategory"
|
|
:categories="categories"
|
|
@refresh="loadCategories"
|
|
/>
|
|
</el-col>
|
|
<el-col :span="19">
|
|
<div class="faq-main unified-shell">
|
|
<div class="filters unified-action-bar">
|
|
<el-input
|
|
v-model="keyword"
|
|
:placeholder="TEXT.common.placeholders.keyword"
|
|
clearable
|
|
@keyup.enter="loadFaqs"
|
|
style="width: 260px"
|
|
/>
|
|
<el-switch v-model="onlyActive" :active-text="TEXT.common.labels.activeOnly" @change="loadFaqs" />
|
|
<div class="spacer" />
|
|
<PermissionAction action="faq.create">
|
|
<el-button type="primary" @click="openForm()">{{ TEXT.modules.knowledgeMedicalConsult.newItem }}</el-button>
|
|
</PermissionAction>
|
|
</div>
|
|
|
|
<FaqList
|
|
:items="faqs"
|
|
:categories="categories"
|
|
:loading="loading"
|
|
:can-edit="canEdit"
|
|
@refresh="loadFaqs"
|
|
/>
|
|
<div class="pagination-wrap" v-if="total > 0">
|
|
<el-pagination
|
|
v-model:current-page="page"
|
|
v-model:page-size="pageSize"
|
|
:page-sizes="[5, 10, 20]"
|
|
:total="total"
|
|
layout="prev, pager, next, sizes, total"
|
|
small
|
|
@current-change="onPageChange"
|
|
@size-change="onPageSizeChange"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<FaqItemForm v-model="showForm" :item="editing" :categories="categories" @success="loadFaqs" />
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, onMounted, ref, watch } from "vue";
|
|
import { ElMessage } from "element-plus";
|
|
import { fetchFaqCategories, fetchFaqItems } from "../api/faqs";
|
|
import FaqCategoryPanel from "../components/FaqCategoryPanel.vue";
|
|
import FaqList from "../components/FaqList.vue";
|
|
import FaqItemForm from "../components/FaqItemForm.vue";
|
|
import { useAuthStore } from "../store/auth";
|
|
import { useStudyStore } from "../store/study";
|
|
import PermissionAction from "../components/PermissionAction.vue";
|
|
import { usePermission } from "../utils/permission";
|
|
import { TEXT } from "../locales";
|
|
|
|
const auth = useAuthStore();
|
|
const study = useStudyStore();
|
|
|
|
const categories = ref<any[]>([]);
|
|
const faqs = ref<any[]>([]);
|
|
const loading = ref(false);
|
|
const page = ref(1);
|
|
const pageSize = ref(10);
|
|
const total = ref(0);
|
|
const keyword = ref("");
|
|
const onlyActive = ref(true);
|
|
const activeCategory = ref("");
|
|
const showForm = ref(false);
|
|
const editing = ref<any | null>(null);
|
|
|
|
const { can } = usePermission();
|
|
const canEdit = computed(() => can("faq.edit"));
|
|
|
|
const loadCategories = async () => {
|
|
try {
|
|
if (!study.currentStudy) return;
|
|
const params: Record<string, any> = {};
|
|
if (study.currentStudy) params.study_id = study.currentStudy.id;
|
|
const { data } = await fetchFaqCategories(params);
|
|
categories.value = data.items || data || [];
|
|
} catch (e: any) {
|
|
ElMessage.error(e?.response?.data?.message || TEXT.common.messages.loadFailed);
|
|
}
|
|
};
|
|
|
|
const loadFaqs = async () => {
|
|
if (!study.currentStudy) return;
|
|
loading.value = true;
|
|
try {
|
|
const params: Record<string, any> = {
|
|
skip: (page.value - 1) * pageSize.value,
|
|
limit: pageSize.value,
|
|
study_id: study.currentStudy.id,
|
|
};
|
|
if (activeCategory.value) params.category_id = activeCategory.value;
|
|
if (keyword.value) params.keyword = keyword.value;
|
|
if (onlyActive.value) params.is_active = true;
|
|
const { data } = await fetchFaqItems(params);
|
|
if (Array.isArray(data)) {
|
|
faqs.value = data;
|
|
total.value = data.length;
|
|
} else {
|
|
faqs.value = data.items || [];
|
|
total.value = data.total || 0;
|
|
}
|
|
} catch (e: any) {
|
|
ElMessage.error(e?.response?.data?.message || TEXT.common.messages.loadFailed);
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
const onPageChange = (p: number) => {
|
|
page.value = p;
|
|
loadFaqs();
|
|
};
|
|
|
|
const onPageSizeChange = (size: number) => {
|
|
pageSize.value = size;
|
|
page.value = 1;
|
|
loadFaqs();
|
|
};
|
|
|
|
watch(activeCategory, () => {
|
|
page.value = 1;
|
|
loadFaqs();
|
|
});
|
|
|
|
const openForm = (row?: any) => {
|
|
editing.value = row || null;
|
|
showForm.value = true;
|
|
};
|
|
|
|
onMounted(async () => {
|
|
if (!auth.user && auth.token) {
|
|
await auth.fetchMe().catch(() => {});
|
|
}
|
|
await loadCategories();
|
|
loadFaqs();
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
.page {
|
|
padding: 0;
|
|
}
|
|
.faq-main {
|
|
background: #fff;
|
|
border: 0;
|
|
border-radius: 0;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
}
|
|
.filters {
|
|
display: flex;
|
|
gap: 8px;
|
|
align-items: center;
|
|
}
|
|
.spacer {
|
|
flex: 1;
|
|
}
|
|
.pagination-wrap {
|
|
padding: 10px 16px 0;
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
}
|
|
</style>
|