管理后台前后端逻辑、UI美化
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
<p class="page-subtitle">{{ TEXT.modules.knowledgeNotes.detailSubtitle }}</p>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<el-button type="primary" @click="goEdit">{{ TEXT.common.actions.edit }}</el-button>
|
||||
<el-button type="primary" :disabled="isReadOnly" @click="goEdit">{{ TEXT.common.actions.edit }}</el-button>
|
||||
<el-button @click="goBack">{{ TEXT.common.actions.back }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -25,16 +25,18 @@
|
||||
:study-id="studyId"
|
||||
entity-type="knowledge_note"
|
||||
:entity-id="noteId"
|
||||
:readonly="isReadOnly"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref } from "vue";
|
||||
import { computed, onMounted, reactive, ref } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useStudyStore } from "../../store/study";
|
||||
import { getKnowledgeNote } from "../../api/knowledgeNotes";
|
||||
import { fetchSites } from "../../api/sites";
|
||||
import AttachmentList from "../../components/attachments/AttachmentList.vue";
|
||||
import { TEXT } from "../../locales";
|
||||
|
||||
@@ -44,6 +46,7 @@ const study = useStudyStore();
|
||||
const loading = ref(false);
|
||||
const noteId = route.params.noteId as string;
|
||||
const studyId = study.currentStudy?.id || "";
|
||||
const sites = ref<any[]>([]);
|
||||
|
||||
const detail = reactive<any>({
|
||||
site_name: "",
|
||||
@@ -52,6 +55,25 @@ const detail = reactive<any>({
|
||||
content: "",
|
||||
});
|
||||
|
||||
const siteActiveMap = computed(() => {
|
||||
const map: Record<string, boolean> = {};
|
||||
sites.value.forEach((site) => {
|
||||
if (site?.name) map[site.name] = !!site.is_active;
|
||||
});
|
||||
return map;
|
||||
});
|
||||
const isReadOnly = computed(() => !!detail.site_name && siteActiveMap.value[detail.site_name] === false);
|
||||
|
||||
const loadSites = async () => {
|
||||
if (!studyId) return;
|
||||
try {
|
||||
const { data } = await fetchSites(studyId, { limit: 500 });
|
||||
sites.value = Array.isArray(data) ? data : data.items || [];
|
||||
} catch {
|
||||
sites.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
const load = async () => {
|
||||
if (!studyId || !noteId) return;
|
||||
loading.value = true;
|
||||
@@ -65,10 +87,19 @@ const load = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const goEdit = () => router.push(`/knowledge/notes/${noteId}/edit`);
|
||||
const goEdit = () => {
|
||||
if (isReadOnly.value) {
|
||||
ElMessage.warning("中心已停用");
|
||||
return;
|
||||
}
|
||||
router.push(`/knowledge/notes/${noteId}/edit`);
|
||||
};
|
||||
const goBack = () => router.push("/knowledge/notes");
|
||||
|
||||
onMounted(load);
|
||||
onMounted(async () => {
|
||||
await loadSites();
|
||||
load();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -11,19 +11,19 @@
|
||||
<el-card>
|
||||
<el-form :model="form" label-width="120px">
|
||||
<el-form-item :label="TEXT.common.fields.site" required>
|
||||
<el-input v-model="form.site_name" :placeholder="TEXT.common.placeholders.input + TEXT.common.fields.site" />
|
||||
<el-input v-model="form.site_name" :disabled="isReadOnly" :placeholder="TEXT.common.placeholders.input + TEXT.common.fields.site" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="TEXT.common.fields.title" required>
|
||||
<el-input v-model="form.title" :placeholder="TEXT.common.placeholders.input + TEXT.common.fields.title" />
|
||||
<el-input v-model="form.title" :disabled="isReadOnly" :placeholder="TEXT.common.placeholders.input + TEXT.common.fields.title" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="TEXT.common.fields.level">
|
||||
<el-input v-model="form.level" :placeholder="TEXT.common.placeholders.input" />
|
||||
<el-input v-model="form.level" :disabled="isReadOnly" :placeholder="TEXT.common.placeholders.input" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="TEXT.common.fields.content" required>
|
||||
<el-input v-model="form.content" type="textarea" :rows="4" :placeholder="TEXT.common.placeholders.input" />
|
||||
<el-input v-model="form.content" :disabled="isReadOnly" type="textarea" :rows="4" :placeholder="TEXT.common.placeholders.input" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="saving" @click="submit">{{ TEXT.common.actions.save }}</el-button>
|
||||
<el-button type="primary" :loading="saving" :disabled="isReadOnly" @click="submit">{{ TEXT.common.actions.save }}</el-button>
|
||||
<el-button @click="goBack">{{ TEXT.common.actions.cancel }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -34,6 +34,7 @@
|
||||
:study-id="studyId"
|
||||
entity-type="knowledge_note"
|
||||
:entity-id="noteId"
|
||||
:readonly="isReadOnly"
|
||||
/>
|
||||
<el-card v-else class="hint-card">
|
||||
<StateEmpty :description="TEXT.modules.knowledgeNotes.uploadHint" />
|
||||
@@ -47,6 +48,7 @@ import { useRoute, useRouter } from "vue-router";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useStudyStore } from "../../store/study";
|
||||
import { createKnowledgeNote, getKnowledgeNote, updateKnowledgeNote } from "../../api/knowledgeNotes";
|
||||
import { fetchSites } from "../../api/sites";
|
||||
import AttachmentList from "../../components/attachments/AttachmentList.vue";
|
||||
import StateEmpty from "../../components/StateEmpty.vue";
|
||||
import { TEXT } from "../../locales";
|
||||
@@ -55,6 +57,7 @@ const route = useRoute();
|
||||
const router = useRouter();
|
||||
const study = useStudyStore();
|
||||
const saving = ref(false);
|
||||
const sites = ref<any[]>([]);
|
||||
|
||||
const noteId = computed(() => route.params.noteId as string | undefined);
|
||||
const isEdit = computed(() => !!noteId.value);
|
||||
@@ -67,6 +70,25 @@ const form = reactive({
|
||||
content: "",
|
||||
});
|
||||
|
||||
const siteActiveMap = computed(() => {
|
||||
const map: Record<string, boolean> = {};
|
||||
sites.value.forEach((site) => {
|
||||
if (site?.name) map[site.name] = !!site.is_active;
|
||||
});
|
||||
return map;
|
||||
});
|
||||
const isReadOnly = computed(() => isEdit.value && !!form.site_name && siteActiveMap.value[form.site_name] === false);
|
||||
|
||||
const loadSites = async () => {
|
||||
if (!studyId.value) return;
|
||||
try {
|
||||
const { data } = await fetchSites(studyId.value, { limit: 500 });
|
||||
sites.value = Array.isArray(data) ? data : data.items || [];
|
||||
} catch {
|
||||
sites.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
const load = async () => {
|
||||
if (!isEdit.value || !studyId.value || !noteId.value) return;
|
||||
try {
|
||||
@@ -84,6 +106,18 @@ const load = async () => {
|
||||
|
||||
const submit = async () => {
|
||||
if (!studyId.value) return;
|
||||
if (isReadOnly.value) {
|
||||
ElMessage.warning("中心已停用");
|
||||
return;
|
||||
}
|
||||
if (!form.site_name) {
|
||||
ElMessage.warning(TEXT.common.messages.required);
|
||||
return;
|
||||
}
|
||||
if (siteActiveMap.value[form.site_name] === false) {
|
||||
ElMessage.warning("中心已停用");
|
||||
return;
|
||||
}
|
||||
saving.value = true;
|
||||
try {
|
||||
const payload = {
|
||||
@@ -110,7 +144,10 @@ const submit = async () => {
|
||||
|
||||
const goBack = () => router.push("/knowledge/notes");
|
||||
|
||||
onMounted(load);
|
||||
onMounted(async () => {
|
||||
await loadSites();
|
||||
load();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user