| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- <template>
- <FlexCol backgroundColor="background.page">
- <FlexCol position="fixed" :top="0" :left="0" :right="0" :zIndex="100">
- <StatusBarSpace backgroundColor="transparent" />
- <NavBar leftButton="back" :iconProps="{ color: 'white', innerStyle: { backgroundColor: 'rgba(0,0,0,0.2)' } }" textColor="white" />
- </FlexCol>
- <FlexCol v-if="errorMessage" :padding="30" :gap="30" center height="100%">
- <Result status="error" :description="errorMessage" />
- <Button type="primary" @click="loadPageConfig">重新加载</Button>
- </FlexCol>
- <SimplePageContentLoader v-else :loader="loader">
- <template v-if="loader.content.value">
- <view class="d-flex flex-col">
- <!-- 头部 -->
- <template v-if="querys.showHead">
- <ImageSwiper
- v-if="loader.content.value.images && loader.content.value.images.length > 0"
- :images="loader.content.value.images"
- height="500rpx"
- />
- <Image
- v-else-if="loader.content.value.image"
- width="100%"
- height="500rpx"
- :radius="15"
- :src="loader.content.value.image"
- mode="widthFix"
- />
- <view v-else class="height-150"></view>
- </template>
- <!-- 标题区域 -->
- <view class="d-flex flex-col p-3">
- <view class="size-ll color-title-text">{{ loader.content.value.title }}</view>
- <view class="d-flex flex-row mt-2">
- <text class="size-s color-text-content-second text-nowrap">{{ DataDateUtils.formatDate(loader.content.value.publishAt, 'YYYY-MM-dd') }}</text>
- </view>
- </view>
- <!-- 归档 -->
- <view v-if="archiveInfo.hasArchive && querys.showArchive" class="mt-3">
- <Box2LineImageRightShadow
- class="w-100"
- titleColor="title-text"
- title2
- :image="archiveInfo.archiveIcon"
- :title="loader.content.value.title"
- desc="点击查看完整文档"
- @click="goArchive(loader.content.value.id)"
- />
- </view>
- <!-- 查询借阅功能按钮 -->
- <view v-if="querys.showBorrow" class="mt-3">
- <Box2LineImageRightShadow
- class="w-100"
- titleColor="title-text"
- title2
- :image="currentCommonCategoryContentDefine?.props.articleBorrow?.icon"
- :title="loader.content.value.title"
- :desc="currentCommonCategoryContentDefine?.props.articleBorrow?.text"
- @click="goBorrow(loader.content.value.title)"
- />
- </view>
- <!-- 源网页 -->
- <view v-if="currentCommonCategoryContentDefine?.props.topButtons" class="mt-3">
- <template v-for="button in currentCommonCategoryContentDefine?.props.topButtons">
- <Box2LineImageRightShadow
- v-if="evaluateButtonVisible(button.visible)"
- class="w-100"
- titleColor="title-text"
- title2
- :image="archiveInfo.archiveIcon"
- :title="button.text"
- :desc="loader.content.value.title"
- @click="executeButtonAction(button.expression)"
- />
- </template>
- </view>
- <!-- 内容 -->
- <view class="p-3 radius-ll bg-light mt-3">
- <Parse
- v-if="loader.content.value.content"
- :content="loader.content.value.content"
- />
- <text v-if="emptyContent">暂无简介</text>
- <text v-if="loader.content.value.from" class="size-s color-text-content-second mr-2 ">
- {{ appConfiguration?.articleMark }}
- {{ loader.content.value?.from }}
- </text>
- </view>
-
- <!-- 推荐 -->
- <view v-if="recommendListLoader.content.value?.length && querys.showRecommend" class="d-flex flex-col p-3">
- <text class="size-base text-bold mb-3">相关推荐</text>
- <Box2LineImageRightShadow
- class="w-100"
- titleColor="title-text"
- v-for="item in recommendListLoader.content.value"
- :key="item.id"
- :image="item.thumbnail || item.image"
- :title="item.title"
- :desc="item.desc"
- :wideImage="true"
- :tags="(item.bottomTags as string[])"
- @click="goDetails(item)"
- />
- </view>
- <ContentNote />
- <LikeFooter :content="loader.content.value">
- <template #left>
- <ArticleCorrect :content="loader.content.value" />
- </template>
- </LikeFooter>
- </view>
- </template>
- </SimplePageContentLoader>
- <Footer text="到底了~" />
- </FlexCol>
- </template>
- <script setup lang="ts">
- import { onShareTimeline, onShareAppMessage } from "@dcloudio/uni-app";
- import { DataDateUtils } from "@imengyu/js-request-transform";
- import { useSimplePageContentLoader } from "@/common/composeabe/SimplePageContentLoader";
- import { useLoadQuerys } from "@/common/composeabe/LoadQuerys";
- import { computed, onMounted, ref } from "vue";
- import { FormatUtils, StringUtils, waitTimeOut } from "@imengyu/imengyu-utils";
- import { injectAppConfiguration } from "@/api/system/useAppConfiguration";
- import { useSimpleDataLoader } from "@/common/composeabe/SimpleDataLoader";
- import { navTo, redirectTo } from "@/components/utils/PageAction";
- import { navCommonDetail, resolveCommonContentFormData } from "./common/CommonContent";
- import { injectCommonCategory } from "./data/CommonCategoryGlobalLoader";
- import { getIsDevtoolsPlatform } from "@/common/utils/MpVersions";
- import type { GetContentDetailItem, GetContentListItem } from "@/api/CommonContent";
- import type { IHomeCommonArticleDetailDefine } from "./data/CommonCategoryDefine";
- import CommonContent, { GetContentListParams } from "@/api/CommonContent";
- import Box2LineImageRightShadow from "../parts/Box2LineImageRightShadow.vue";
- import LikeFooter from "../parts/LikeFooter.vue";
- import Image from "@/components/basic/Image.vue";
- import ArticleCorrect from "../parts/ArticleCorrect.vue";
- import ImageSwiper from "../parts/ImageSwiper.vue";
- import IconExcel from '@/components/images/files/excel.png';
- import IconPowerpoint from '@/components/images/files/powerpoint.png';
- import IconUnknown from '@/components/images/files/unknown.png';
- import IconWord from '@/components/images/files/word.png';
- import IconPdf from '@/components/images/files/pdf.png';
- import NewsIndexContent from "@/api/news/NewsIndexContent";
- import SimplePageContentLoader from "@/common/components/SimplePageContentLoader.vue";
- import ContentNote from "../parts/ContentNote.vue";
- import Parse from "@/components/display/parse/Parse.vue";
- import Icon from "@/components/basic/Icon.vue";
- import FlexCol from "@/components/layout/FlexCol.vue";
- import Footer from "@/components/display/Footer.vue";
- import NavBar from "@/components/nav/NavBar.vue";
- import StatusBarSpace from "@/components/layout/space/StatusBarSpace.vue";
- import dynamicScript from "./data/CommonCategoryScript";
- export interface CommonArticleDetailProps {
- /**
- * 查询借阅功能按钮
- */
- articleBorrow: {
- /**
- * 查询借阅功能按钮链接
- */
- url: string,
- /**
- * 查询借阅功能按钮文本
- */
- text: string,
- /**
- * 查询借阅功能按钮图标
- */
- icon: string,
- },
- /**
- * 顶部按钮配置
- */
- topButtons: {
- /**
- * 按钮可见性表达式
- */
- visible: string,
- /**
- * 按钮文本
- */
- text: string,
- /**
- * 按钮图标
- */
- icon: string,
- /**
- * 按钮动作表达式
- */
- expression: string,
- }[],
- /**
- * TODO: 顶部显示信息配置
- */
- topShowInfos: {
- /**
- * 显示信息键
- */
- key: string,
- /**
- * 显示信息前缀
- */
- prefix: string,
- /**
- * 显示信息表达式
- */
- expression: string,
- }[],
- /**
- * 推荐详情处理函数
- */
- recommendDetailHandler: string,
- }
- const { querys } = useLoadQuerys({
- id: 0,
- mainBodyColumnId: 0,
- modelId: 0,
- /**
- * 是否显示推荐
- */
- showRecommend: true,
- /**
- * 是否显示头部
- * @default true
- */
- showHead: true,
- /**
- * 是否显示归档
- * @default true
- */
- showArchive: true,
- /**
- * 是否显示查询借阅功能按钮
- * @default false
- */
- showBorrow: false,
- /**
- * 是否自动跳转外部链接
- * @default 'auto'
- * @description 'auto' 自动跳转,'manual' 手动跳转,'none' 不跳转
- */
- navToExternalLink: 'auto',
- /**
- * 顶部显示信息
- * @default 'all'
- * @description 'all' 显示所有信息,'none' 不显示任何信息,多个信息用逗号分隔
- */
- topShowInfos: 'all',
- }, (t) => loader.loadData(t));
- const loader = useSimplePageContentLoader<
- GetContentDetailItem,
- { id: number }
- >(async (params) => {
- if (!params)
- throw new Error("!params");
- await waitTimeOut(200);
- const res = await NewsIndexContent.getContentDetail(params.id);
- uni.setNavigationBarTitle({ title: res.title });
- if (querys.value.navToExternalLink === 'auto' && (!res.content || res.content.trim() === '') && res.externalLink) {
- goExternalLink(res.externalLink);
- } else if (querys.value.navToExternalLink !== 'none' && res.externalLink) {
- goExternalLink(res.externalLink);
- }
- return res;
- });
- const currentCommonCategoryContentDefine = ref<IHomeCommonArticleDetailDefine>();
- const commonCategory = injectCommonCategory();
- const appConfiguration = injectAppConfiguration();
- const errorMessage = ref('');
- const emptyContent = computed(() => (loader.content.value?.content || '').trim() === '')
- const archiveInfo = computed(() => {
- const hasArchive = Boolean(loader.content.value?.archives);
- let fileIcon = IconUnknown;
- const ext = StringUtils.path.getFileExt(loader.content.value?.archives || '');
- switch (ext) {
- case 'excel':
- case 'xls':
- case 'xlsx':
- fileIcon = IconExcel;
- break;
- case 'powerpoint':
- case 'ppt':
- case 'pptx':
- fileIcon = IconPowerpoint;
- break;
- case 'word':
- case 'docx':
- case 'doc':
- case 'txt':
- case 'rtf':
- fileIcon = IconWord;
- break;
- case 'pdf':
- fileIcon = IconPdf;
- break;
- }
- return {
- hasArchive,
- archiveIcon: hasArchive ? fileIcon : IconUnknown,
- }
- })
- const recommendListLoader = useSimpleDataLoader(async () => {
- if (!querys.value.modelId)
- return []
- const res = (await CommonContent.getContentList(new GetContentListParams()
- .setModelId(querys.value.modelId)
- .setMainBodyColumnId(querys.value.mainBodyColumnId)
- , 1, 10)).list
- .filter((p) => p.id !== querys.value.id)
- return resolveCommonContentFormData(res);
- });
- function evaluateButtonVisible(expression: string) {
- return dynamicScript.execute(expression, {
- main: loader.content.value || {},
- }) as boolean;
- }
- function executeButtonAction(expression: string) {
- dynamicScript.execute(expression, {
- main: loader.content.value || {},
- }) as any;
- }
- function goExternalLink(url: string) {
- redirectTo('/pages/article/web/ewebview', { url });
- }
- function goArchive(id: number) {
- const archiveUrl = loader.content.value?.archives || '';
- if (!archiveUrl)
- return;
- const ext = StringUtils.path.getFileExt(archiveUrl);
- switch (ext) {
- case 'excel':
- case 'xls':
- case 'xlsx':
- case 'powerpoint':
- case 'ppt':
- case 'pptx':
- case 'word':
- case 'docx':
- case 'doc':
- case 'txt':
- case 'rtf':
- case 'pdf': {
- uni.showLoading({ title: '下载中...' })
- uni.downloadFile({
- url: archiveUrl,
- success: (res) => {
- uni.hideLoading()
- uni.openDocument({
- filePath: res.tempFilePath,
- })
- },
- fail: (res) => {
- console.error(res);
- uni.hideLoading()
- uni.showToast({
- title: '下载文件失败,请检查网络',
- icon: 'none',
- })
- },
- })
- break;
- }
- case 'htm':
- case 'html':
- navTo('/pages/article/web/ewebview', {
- url: archiveUrl,
- });
- default:
- uni.showToast({
- title: '抱歉,不支持打开该文件',
- icon: 'none',
- })
- break;
- }
- }
- function goDetails(item: GetContentListItem) {
- const script = currentCommonCategoryContentDefine.value?.props.recommendDetailHandler;
- if (script) {
- dynamicScript.execute(script, {
- main: item,
- }) as any;
- return;
- }
- navCommonDetail({
- id: item.id,
- mainBodyColumnId: item.mainBodyColumnId,
- modelId: item.modelId,
- });
- }
- function goBorrow(title: string) {
- navTo('/pages/article/web/ewebview', {
- url: FormatUtils.formatString(currentCommonCategoryContentDefine.value?.props.articleBorrow?.url || '', title)
- });
- }
- function getPageShareData() {
- if (!loader.content.value)
- return { title: '文章详情', imageUrl: '' }
- return {
- title: loader.content.value.title,
- imageUrl: loader.content.value.images[0],
- }
- }
- async function loadPageConfig() {
- if (getIsDevtoolsPlatform()) {
- await waitTimeOut(500);
- }
- const pageConfigName = 'common-details';
- let currentCommonCategoryDefine = commonCategory.value.page
- .find((item) => item.name === pageConfigName);
- if (!currentCommonCategoryDefine) {
- await waitTimeOut(1000);
- currentCommonCategoryDefine = commonCategory.value.page.find((item) => item.name === pageConfigName);
- }
- if (!currentCommonCategoryDefine) {
- errorMessage.value = '未找到指定的分类配置:' + pageConfigName;
- return;
- }
- if (currentCommonCategoryDefine.content.type !== 'CommonDetails') {
- errorMessage.value = '分类配置:' + pageConfigName + ' 不是默认详情类型';
- return;
- }
- currentCommonCategoryContentDefine.value = currentCommonCategoryDefine.content;
- uni.setNavigationBarTitle({
- title: currentCommonCategoryDefine.title || '',
- })
- }
- onMounted(() => {
- loadPageConfig();
- });
- onShareTimeline(() => {
- return getPageShareData();
- })
- onShareAppMessage(() => {
- return getPageShareData();
- })
- </script>
|