fix: 优化文章列表和分类加载逻辑
This commit is contained in:
parent
739f265d09
commit
86ab607965
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="bg-gray-100 min-h-screen">
|
<view class="bg-gray-100 min-h-screen">
|
||||||
<!-- Category Tabs -->
|
<!-- Category Tabs -->
|
||||||
<scroll-view scroll-x class="bg-white whitespace-nowrap px-15 py-10 sticky top-0 z-10 w-full"
|
<!-- <scroll-view scroll-x class="bg-white whitespace-nowrap px-15 py-10 sticky top-0 z-10 w-full"
|
||||||
:show-scrollbar="false">
|
:show-scrollbar="false">
|
||||||
<view v-for="(tab, index) in tabs" :key="index"
|
<view v-for="(tab, index) in tabs" :key="index"
|
||||||
class="inline-block px-15 py-5 mr-10 text-sm rounded-full border transition-colors" :class="[
|
class="inline-block px-15 py-5 mr-10 text-sm rounded-full border transition-colors" :class="[
|
||||||
@ -11,7 +11,7 @@
|
|||||||
]" @click="selectCate(tab.value)">
|
]" @click="selectCate(tab.value)">
|
||||||
{{ tab.name }}
|
{{ tab.name }}
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view> -->
|
||||||
|
|
||||||
<!-- List -->
|
<!-- List -->
|
||||||
<view v-if="loading && list.length === 0" class="loading-container">
|
<view v-if="loading && list.length === 0" class="loading-container">
|
||||||
@ -50,7 +50,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
|
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import api from "@/utils/api.js";
|
import api from "@/utils/api.js";
|
||||||
@ -60,15 +60,149 @@ const env = __VITE_ENV__;
|
|||||||
const defaultCorpId = env.MP_CORP_ID;
|
const defaultCorpId = env.MP_CORP_ID;
|
||||||
|
|
||||||
const corpId = ref("");
|
const corpId = ref("");
|
||||||
|
const enabledIds = ref([]);
|
||||||
const tabs = ref([{ name: "全部", value: "" }]);
|
const tabs = ref([{ name: "全部", value: "" }]);
|
||||||
const activeCateId = ref("");
|
const activeCateId = ref("");
|
||||||
|
|
||||||
|
const allArticles = ref([]);
|
||||||
const list = ref([]);
|
const list = ref([]);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const page = ref(1);
|
const page = ref(1);
|
||||||
const pageSize = 20;
|
const pageSize = 20;
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
|
const uniqStrings = (items) => {
|
||||||
|
const seen = new Set();
|
||||||
|
const out = [];
|
||||||
|
for (const item of items) {
|
||||||
|
const s = typeof item === "string" ? item.trim() : "";
|
||||||
|
if (!s || seen.has(s)) continue;
|
||||||
|
seen.add(s);
|
||||||
|
out.push(s);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseIdsParam = (raw) => {
|
||||||
|
if (!raw) return [];
|
||||||
|
const text = Array.isArray(raw) ? raw.join(",") : String(raw);
|
||||||
|
const decoded = decodeURIComponent(text);
|
||||||
|
return uniqStrings(decoded.split(","));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAllTab = () => ({ name: tabs.value?.[0]?.name || "全部", value: "" });
|
||||||
|
|
||||||
|
const getArticleCateIds = (article) => {
|
||||||
|
const ids = [];
|
||||||
|
if (!article) return ids;
|
||||||
|
|
||||||
|
if (Array.isArray(article.cateIds)) ids.push(...article.cateIds);
|
||||||
|
if (typeof article.cateIds === "string") ids.push(article.cateIds);
|
||||||
|
if (typeof article.cateId === "string") ids.push(article.cateId);
|
||||||
|
|
||||||
|
if (typeof article.categoryId === "string") ids.push(article.categoryId);
|
||||||
|
if (Array.isArray(article.categoryIds)) ids.push(...article.categoryIds);
|
||||||
|
if (typeof article.categoryIds === "string") ids.push(article.categoryIds);
|
||||||
|
|
||||||
|
if (Array.isArray(article.cateList)) {
|
||||||
|
ids.push(
|
||||||
|
...article.cateList.map((c) => c?._id || c?.id).filter((v) => typeof v === "string")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (article.cate && typeof article.cate === "object") {
|
||||||
|
const v = article.cate._id || article.cate.id;
|
||||||
|
if (typeof v === "string") ids.push(v);
|
||||||
|
}
|
||||||
|
if (typeof article.cate === "string") ids.push(article.cate);
|
||||||
|
|
||||||
|
return uniqStrings(ids);
|
||||||
|
};
|
||||||
|
|
||||||
|
const filteredArticles = computed(() => {
|
||||||
|
const cateId = activeCateId.value;
|
||||||
|
if (!cateId) return allArticles.value;
|
||||||
|
return allArticles.value.filter((article) => getArticleCateIds(article).includes(cateId));
|
||||||
|
});
|
||||||
|
|
||||||
|
const relatedCateIdSet = computed(() => {
|
||||||
|
const set = new Set();
|
||||||
|
for (const article of allArticles.value) {
|
||||||
|
for (const cateId of getArticleCateIds(article)) set.add(cateId);
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
});
|
||||||
|
|
||||||
|
const refreshList = (reset = false) => {
|
||||||
|
if (reset) {
|
||||||
|
page.value = 1;
|
||||||
|
list.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = filteredArticles.value || [];
|
||||||
|
total.value = rows.length;
|
||||||
|
|
||||||
|
const start = (page.value - 1) * pageSize;
|
||||||
|
const end = start + pageSize;
|
||||||
|
const slice = rows.slice(start, end);
|
||||||
|
|
||||||
|
if (page.value === 1) list.value = slice;
|
||||||
|
else list.value = [...list.value, ...slice];
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadEnabledArticles = async () => {
|
||||||
|
if (!corpId.value || enabledIds.value.length === 0) {
|
||||||
|
allArticles.value = [];
|
||||||
|
tabs.value = [getAllTab()];
|
||||||
|
refreshList(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (loading.value) return;
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const ids = enabledIds.value;
|
||||||
|
const res = await api("getArticleByIds", { corpId: corpId.value, ids: ids.join(",") });
|
||||||
|
const rows = res && Array.isArray(res.list) ? res.list : [];
|
||||||
|
|
||||||
|
const order = new Map(ids.map((id, idx) => [id, idx]));
|
||||||
|
allArticles.value = rows
|
||||||
|
.map((r) => ({
|
||||||
|
...r,
|
||||||
|
time: r?.createTime ? dayjs(r.createTime).format("YYYY-MM-DD") : "",
|
||||||
|
}))
|
||||||
|
.sort((a, b) => (order.get(a?._id) ?? 1e9) - (order.get(b?._id) ?? 1e9));
|
||||||
|
} catch (err) {
|
||||||
|
console.error("loadEnabledArticles failed:", err);
|
||||||
|
allArticles.value = [];
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadTabs = async () => {
|
||||||
|
if (!corpId.value) return;
|
||||||
|
|
||||||
|
const related = relatedCateIdSet.value;
|
||||||
|
if (!related.size) {
|
||||||
|
tabs.value = [getAllTab()];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await api("getArticleCateList", { corpId: corpId.value });
|
||||||
|
const cates = res && Array.isArray(res.list) ? res.list : [];
|
||||||
|
const visible = cates.filter((c) => related.has(c?._id));
|
||||||
|
|
||||||
|
tabs.value = [
|
||||||
|
getAllTab(),
|
||||||
|
...visible.map((i) => ({ name: i.label || i.name || "", value: i._id })),
|
||||||
|
];
|
||||||
|
} catch (err) {
|
||||||
|
console.error("loadTabs failed:", err);
|
||||||
|
tabs.value = [getAllTab()];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const loadCates = async () => {
|
const loadCates = async () => {
|
||||||
if (!corpId.value) return;
|
if (!corpId.value) return;
|
||||||
try {
|
try {
|
||||||
@ -118,7 +252,7 @@ const loadList = async (reset = false) => {
|
|||||||
const selectCate = async (cateId) => {
|
const selectCate = async (cateId) => {
|
||||||
if (activeCateId.value === cateId) return;
|
if (activeCateId.value === cateId) return;
|
||||||
activeCateId.value = cateId;
|
activeCateId.value = cateId;
|
||||||
await loadList(true);
|
refreshList(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
function goToDetail(item) {
|
function goToDetail(item) {
|
||||||
@ -128,15 +262,18 @@ function goToDetail(item) {
|
|||||||
|
|
||||||
onLoad(async (options) => {
|
onLoad(async (options) => {
|
||||||
corpId.value = options?.corpId || defaultCorpId || "";
|
corpId.value = options?.corpId || defaultCorpId || "";
|
||||||
await loadCates();
|
enabledIds.value = parseIdsParam(options?.ids);
|
||||||
await loadList(true);
|
activeCateId.value = "";
|
||||||
|
await loadEnabledArticles();
|
||||||
|
await loadTabs();
|
||||||
|
refreshList(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
onReachBottom(() => {
|
onReachBottom(() => {
|
||||||
if (loading.value) return;
|
if (loading.value) return;
|
||||||
if (list.value.length >= total.value) return;
|
if (list.value.length >= total.value) return;
|
||||||
page.value += 1;
|
page.value += 1;
|
||||||
loadList(false);
|
refreshList(false);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import api from '@/utils/api';
|
import api from '@/utils/api';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -38,38 +38,52 @@ const props = defineProps({
|
|||||||
|
|
||||||
const articles = ref([]);
|
const articles = ref([]);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const page = ref(1);
|
|
||||||
const pageSize = ref(3);
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const pageSize = 3;
|
||||||
|
|
||||||
|
const qrcode = computed(() => {
|
||||||
|
const qrcodes = props.team && Array.isArray(props.team.qrcodes) ? props.team.qrcodes : [];
|
||||||
|
return qrcodes[0] || {};
|
||||||
|
});
|
||||||
|
|
||||||
|
const articleIds = computed(() => {
|
||||||
|
const configured = qrcode.value && Array.isArray(qrcode.value.articles) ? qrcode.value.articles : [];
|
||||||
|
const ids = configured.map((item) => item?._id).filter((id) => typeof id === "string" && id.trim());
|
||||||
|
return qrcode.value?.enableAnnounce === "YES" ? ids : [];
|
||||||
|
});
|
||||||
|
|
||||||
function goToDetail(article) {
|
function goToDetail(article) {
|
||||||
if (!article?._id) return;
|
if (!article?._id) return;
|
||||||
uni.navigateTo({ url: `/pages/article/article-detail?id=${article._id}` });
|
uni.navigateTo({ url: `/pages/article/article-detail?id=${article._id}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadArticles = async (reset = false) => {
|
const loadArticles = async () => {
|
||||||
const corpId = props.team?.corpId || "";
|
const corpId = props.team?.corpId || "";
|
||||||
if (!corpId || loading.value) return;
|
const ids = articleIds.value;
|
||||||
if (reset) {
|
|
||||||
page.value = 1;
|
if (!corpId || ids.length === 0) {
|
||||||
articles.value = [];
|
articles.value = [];
|
||||||
total.value = 0;
|
total.value = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (loading.value) return;
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
const params = {
|
const res = await api("getArticleByIds", { corpId, ids: ids.join(",") }, false);
|
||||||
corpId,
|
const rows = res && Array.isArray(res.list) ? res.list : [];
|
||||||
page: page.value,
|
|
||||||
pageSize: pageSize.value,
|
const order = new Map(ids.map((id, idx) => [id, idx]));
|
||||||
enable: true,
|
const sorted = rows
|
||||||
};
|
.slice()
|
||||||
const res = await api("getArticleList", params, false);
|
.sort((a, b) => (order.get(a?._id) ?? 1e9) - (order.get(b?._id) ?? 1e9));
|
||||||
const list = res && Array.isArray(res.list) ? res.list : [];
|
|
||||||
total.value = Number(res?.total) || 0;
|
total.value = sorted.length;
|
||||||
if (page.value === 1) articles.value = list;
|
articles.value = sorted.slice(0, pageSize);
|
||||||
else articles.value = [...articles.value, ...list];
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("loadArticles failed:", err);
|
console.error("loadArticles failed:", err);
|
||||||
|
articles.value = [];
|
||||||
|
total.value = 0;
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
@ -77,22 +91,20 @@ const loadArticles = async (reset = false) => {
|
|||||||
|
|
||||||
function toMorePage() {
|
function toMorePage() {
|
||||||
const corpId = props.team?.corpId || "";
|
const corpId = props.team?.corpId || "";
|
||||||
if (!corpId) return;
|
const ids = articleIds.value;
|
||||||
uni.navigateTo({ url: `/pages/article/article-cate-list?corpId=${corpId}` });
|
if (!corpId || ids.length === 0) return;
|
||||||
|
uni.navigateTo({ url: `/pages/article/article-cate-list?corpId=${corpId}&ids=${encodeURIComponent(ids.join(","))}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.team?.corpId,
|
() => ({ corpId: props.team?.corpId || "", ids: articleIds.value.join(",") }),
|
||||||
async (corpId) => {
|
async ({ corpId, ids }) => {
|
||||||
if (!corpId) {
|
if (!corpId || !ids) {
|
||||||
articles.value = [];
|
articles.value = [];
|
||||||
total.value = 0;
|
total.value = 0;
|
||||||
page.value = 1;
|
|
||||||
pageSize.value = 3;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pageSize.value = 3;
|
await loadArticles();
|
||||||
await loadArticles(true);
|
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user