Procházet zdrojové kódy

📦 修改细节问题

快乐的梦鱼 před 13 hodinami
rodič
revize
05d4e2a34f

+ 1 - 1
src/api/CommonContent.ts

@@ -283,7 +283,7 @@ export class GetContentDetailItem extends DataModel<GetContentDetailItem> {
         this.associationMeFirstTitle = this.associationMeList[0]?.title || ''
       }
       if (this.otherLevel) {
-        this.otherLevelCount = this.otherLevel.length
+        this.otherLevelCount = this.otherLevel.length + '个'
       }
       this.titleBox = Boolean(this.deathBirth);
     }

+ 5 - 4
src/common/composeabe/LoadQuerys.ts

@@ -16,17 +16,18 @@ export function useLoadQuerys<T extends Record<string, any>>(
   onLoad((_querys) => {
     rawQuerys.value = _querys || {};
     if (_querys) {
-      for (const key in querys.value) {
-        const isDefined = _querys[key] !== undefined;
+      for (const key in defaults) {
+        const isDefined = _querys[key] !== undefined && _querys[key] !== 'undefined';
         if (typeof defaults[key] === 'number')
           (querys.value as Record<string, any>)[key] = isDefined ? Number(_querys[key]) : defaults[key]; 
         else if (typeof defaults[key] === 'boolean')
-          (querys.value as Record<string, any>)[key] = isDefined ? Boolean(_querys[key]) : defaults[key]; 
+          (querys.value as Record<string, any>)[key] = isDefined ? Boolean(_querys[key]) && _querys[key] != 'false' : defaults[key]; 
         else if (typeof defaults[key] === 'object')
           (querys.value as Record<string, any>)[key] = isDefined ? JSON.parse(decodeURIComponent(_querys[key])) : defaults[key]; 
         else
-          querys.value[key] = isDefined ? decodeURIComponent(_querys[key]) as any : defaults[key];
+          querys.value[key] = isDefined ? decodeURIComponent(decodeURIComponent(_querys[key])) as any : defaults[key];
       }
+      console.log('querys', querys.value);
     }
     nextTick(() => {
       afterLoad?.(querys.value);

+ 6 - 3
src/components/utils/PageAction.ts

@@ -35,7 +35,7 @@ function redirectTo(url: string, data: Record<string, unknown> = {}) {
   var dataString = '';
 
   for (const key in data) {
-    if (Object.prototype.hasOwnProperty.call(data, key))
+    if (Object.prototype.hasOwnProperty.call(data, key) && data[key] !== undefined && data[key] !== null)
       dataString += `&${key}=${data[key]}`;
   }
 
@@ -58,8 +58,11 @@ function navTo(url: string, data: Record<string, unknown> = {}) {
     data = url[1]
     url = url[0]
   }
-  for (const key in data)
-    dataString += `&${key}=${encodeURIComponent('' + data[key])}`;
+  for (const key in data) {
+    const d = data[key]
+    if (d !== undefined && d !== null)
+      dataString += `&${key}=${encodeURIComponent('' + d)}`;
+  }
 
   uni.navigateTo({ 
     url: url + (url.includes('?') ? '&' : '?') + dataString,

+ 2 - 66
src/pages/article/common/CommonContent.ts

@@ -1,20 +1,12 @@
-import CommonContent, { GetContentListItem, GetContentListParams } from "@/api/CommonContent";
-import { useSimpleDataLoader, type ISimpleDataLoader } from "@/common/composeabe/SimpleDataLoader";
+import { GetContentListItem, GetContentListParams } from "@/api/CommonContent";
 import { navTo } from "@/components/utils/PageAction";
-import type { IHomeCommonCategoryListTabListDataSolve } from "../data/CommonCategoryDefine";
+import { type IHomeCommonCategoryListTabListDataSolve } from "../data/CommonCategoryDefine";
 import { DateUtils } from "@imengyu/imengyu-utils";
 
 /**
  * 通用内容首页小列表控制代码组合
  */
 
-export interface IHomeCommonCategoryBlock {
-  type: 'CommonCategoryBlock',
-  loader: ISimpleDataLoader<GetContentListItem[], any>;
-  goDetail: (i: GetContentListItem) => void;
-  goList: () => void; 
-}
-
 export function navCommonDetail(p: {
   id: number,
   title?: string,
@@ -111,60 +103,4 @@ export function resolveCommonContentSolveProps(res: GetContentListItem[], dataSo
   for (const solve of dataSolve)
     res = resolveCommonContentData[solve]?.(res) || res;
   return res;
-}
-
-export interface HomeCommonCategoryBlockProps {
-  title?: string,
-  type?: '',
-  mainBodyColumnId?: string|number|number[],
-  modelId?: number,
-  itemType?: string,
-  detailsPage: string,
-  count?: number,
-  params?: Record<string, any>,
-  dataSolve?: IHomeCommonCategoryListTabListDataSolve[],
-}
-
-/**
- * 专用于通用内容的首页小列表控制代码组合
- * @param p 
- * @returns 
- */
-export function useHomeCommonCategoryBlock(p: HomeCommonCategoryBlockProps, loadWhenMounted = true) : IHomeCommonCategoryBlock {
-  function goDetail(i: GetContentListItem) {
-    navTo(p.detailsPage === 'byContent' ? 
-      resolveCommonContentGetPageDetailUrlAuto(i): 
-      p.detailsPage, 
-    {
-      mainBodyColumnId: p.mainBodyColumnId,
-      modelId: p.modelId,
-      id: i.id,
-    }) 
-  }
-  function goList() {
-    navCommonList({
-      title: p.title,
-      mainBodyColumnId: typeof p.mainBodyColumnId == 'object' ? 
-        p.mainBodyColumnId.join(',') : 
-        p.mainBodyColumnId,
-      modelId: p.modelId,
-      itemType: p.itemType,
-      dataSolve: p.dataSolve || [],
-      detailsPage: p.detailsPage,
-    }) 
-  }
-  const loader = useSimpleDataLoader(async () => {
-    let res = (await CommonContent.getContentList(new GetContentListParams().setSelfValues({
-      mainBodyColumnId: p.mainBodyColumnId,
-      modelId: p.modelId,
-      ...p.params,
-    }), 1, p.count ?? 4)).list;
-    return resolveCommonContentSolveProps(res, p.dataSolve || []);;
-  }, loadWhenMounted);
-  return {
-    type: 'CommonCategoryBlock',
-    loader,
-    goDetail,
-    goList,
-  }
 }

+ 16 - 2
src/pages/article/common/CommonListPage.vue

@@ -132,7 +132,8 @@
         </view>
         <view v-if="itemType.endsWith('-2') && listLoader.list.value.length % 2 != 0" class="width-1-2" />
       </view>
-      <SimplePageListLoader :loader="listLoader" />
+      <Empty v-if="listLoader.list.value.length == 0" :description="emptyText" />
+      <SimplePageListLoader v-else :loader="listLoader" />
     </template>
   </view>
 </template>
@@ -148,6 +149,7 @@ import SimpleDropDownPicker, { type SimpleDropDownPickerItem } from '@/common/co
 import AppCofig from '@/common/config/AppCofig';
 import Tabs from '@/components/nav/Tabs.vue';
 import SearchBar from '@/components/form/SearchBar.vue';
+import Empty from '@/components/feedback/Empty.vue';
 import { resolveCommonContentGetPageDetailUrlAuto } from './CommonContent';
 import type { CommonListPageItemType } from './CommonListPage';
 
@@ -278,7 +280,12 @@ export interface CommonListPageProps {
    * 挂载时是否加载数据
    * @default true
    */
-  loadMounted?: boolean
+  loadMounted?: boolean,
+  /**
+   * 空数据时显示的文本
+   * @default '暂无数据'
+   */
+  emptyText?: string,
 }
 
 const props = withDefaults(defineProps<CommonListPageProps>(), {
@@ -298,6 +305,7 @@ const props = withDefaults(defineProps<CommonListPageProps>(), {
   hasPadding: true,
   startTabIndex: undefined,
   loadMounted: true,
+  emptyText: '暂无数据',
 })
 
 const emit = defineEmits([ 'goCustomDetails' ])
@@ -396,6 +404,7 @@ function goDetails(item: any, id: number) {
         return;
       navTo(item.page, { 
         ...item.params, 
+        ...props.detailsParams, 
         id 
       })
       return; 
@@ -434,6 +443,11 @@ watch(() => props.dropDownNames.length, () => {
   loadDropDownValues();
   listLoader.loadData(undefined, true);
 });
+watch(() => props.title, () => {
+  if (props.title) {
+    uni.setNavigationBarTitle({ title: props.title })
+  }
+});
 
 defineExpose({
   load: () => {

+ 2 - 4
src/pages/article/data/CommonCategoryBlocks.ts

@@ -1,12 +1,10 @@
-import type { CommonContentApi } from "@/api/CommonContent";
-import type { IHomeCommonCategoryBlock, HomeCommonCategoryBlockProps } from "../common/CommonContent";
 import type { IHomeCommonCategoryListTabNestCategoryItemDefine } from "./CommonCategoryDefine";
-import type { IHomeCommonCategoryDynamicDataDetailContent } from "./CommonCategoryDynamicData";
+import type { IHomeCommonCategoryDynamicData, IHomeCommonCategoryDynamicDataDetailContent } from "./CommonCategoryDynamicData";
 
 export interface CategoryDefine extends Omit<IHomeCommonCategoryListTabNestCategoryItemDefine, 'type'> {
   title: string;
   showTitle: boolean;
-  content: CommonContentApi|IHomeCommonCategoryBlock|HomeCommonCategoryBlockProps|IHomeCommonCategoryDynamicDataDetailContent|null;
+  content: IHomeCommonCategoryDynamicData|IHomeCommonCategoryDynamicDataDetailContent|null;
   type?: 'article'|'large-image2'|'horizontal-large'|'large-image'|'large-grid2'|'small-grid2'|'simple-article'|'simple-text'
     |'default'
     |'CalendarBlock'|'StatsBlock'|'MapBlock'|'AudioBlock'

+ 131 - 81
src/pages/article/data/CommonCategoryBlocks.vue

@@ -191,8 +191,8 @@
 
 <script setup lang="ts">;
 import { computed, onMounted, watch, type PropType } from 'vue';
-import CommonContent, { CommonContentApi, GetContentListItem, GetContentListParams } from '@/api/CommonContent';
-import { navCommonDetail, navCommonList, resolveCommonContentGetPageDetailUrlAuto, resolveCommonContentSolveProps, useHomeCommonCategoryBlock, type HomeCommonCategoryBlockProps, type IHomeCommonCategoryBlock } from '../common/CommonContent';
+import CommonContent, { GetContentListItem, GetContentListParams } from '@/api/CommonContent';
+import { navCommonDetail, navCommonList, resolveCommonContentGetPageDetailUrlAuto, resolveCommonContentSolveProps } from '../common/CommonContent';
 import { useSimpleDataLoader } from '@/common/composeabe/SimpleDataLoader';
 import { navTo } from '@/components/utils/PageAction';
 import HomeTitle from '@/pages/parts/HomeTitle.vue';
@@ -208,8 +208,9 @@ import MapCategoryBlock from '@/pages/blocks/MapBlock.vue';
 import Image from '@/components/basic/Image.vue';
 import AppCofig from '@/common/config/AppCofig';
 import type { CategoryDefine } from './CommonCategoryBlocks';
-import type { IHomeCommonCategoryDynamicDataDetailContent } from './CommonCategoryDynamicData';
+import { CommonCategoryDynamicDataSerializedApi, doGetDynamicListDataParams, type IHomeCommonCategoryDynamicDataDetailContent } from './CommonCategoryDynamicData';
 import AudioBlock from '@/pages/blocks/AudioBlock.vue';
+import { toast } from '@/components/utils/DialogAction';
 
 const props = defineProps({
   /**
@@ -218,7 +219,14 @@ const props = defineProps({
   categoryDefine: {
     type: Array as PropType<CategoryDefine[]>,
     default: () => [],
-  }
+  },
+  /**
+   * 父级数据
+   */
+  parentData: {
+    type: Object as PropType<any>,
+    default: () => {},
+  },
 });
 
 const categoryDatas = computed(() => props.categoryDefine.map(item => { 
@@ -232,89 +240,131 @@ const categoryDatas = computed(() => props.categoryDefine.map(item => {
       },
       data: null,
     };
+  return {
+    ...item,
+    detailsPage: (dataItem: GetContentListItem) => {
+      const id = dataItem.id;
+      let modelId = 0;
+      let mainBodyColumnId : string|number|number[]|undefined = undefined;
+      switch (item.data.type) {
+        case 'commonContent':
+        case 'serializedApi': {
+          const params = doGetDynamicListDataParams(item.data);
+          modelId = params.modelId;
+          mainBodyColumnId = params.mainBodyColumnId;
+          break;
+        }
+        case 'detailContent':
+        case 'parentKey':
+        case 'request':
+          toast(`此配置选项不支持默认的详情页面跳转!`);
+          console.warn(`此配置选项不支持默认的详情页面跳转!`);
+          return;
+      }  
 
-  const defaultDetailsPageHandler = (dataItem: GetContentListItem) => {
-    const id = dataItem.id;
-    const content = item.content as CommonContentApi;
-    if (item.detailsPage) {
-      if (item.detailsPage === 'byContent')
-        navTo(resolveCommonContentGetPageDetailUrlAuto(dataItem), { id });
-      else
-        navTo(item.detailsPage, { id });
-    } else {
-      navCommonDetail({
-        id,
-        mainBodyColumnId: content.mainBodyColumnId,
-        modelId: content.modelId,
-      })
-    }
-  };
-  if (item.content instanceof CommonContentApi) {
-    return {
-      ...item,
-      detailsPage: defaultDetailsPageHandler,
-      morePage: () => {
-        const content = item.content as CommonContentApi;
-        if (item.morePage) {
-          navTo(item.morePage, {});
-        } else {
-          let mainBodyColumnId : any = content.mainBodyColumnId;
-          if (item.data.type === 'serializedApi' && item.data.params?.mainBodyColumnId)
-            mainBodyColumnId = item.data.params.mainBodyColumnId;
-          navCommonList({
-            title: item.title,
-            mainBodyColumnId: mainBodyColumnId,
-            modelId: content.modelId,
-            detailsPage: item.detailsPage,
-            dataSolve: item.dataSolve || [],
-            itemType: item.itemType,
-          })
+      const params = { id, mainBodyColumnId, modelId };
+      if (item.detailsPage) {
+        if (item.detailsPage === 'disabled')
+          return;
+        else if (item.detailsPage === 'byContent')
+          navTo(resolveCommonContentGetPageDetailUrlAuto(dataItem), params);
+        else
+          navTo(item.detailsPage, params);
+      } else {
+        navCommonDetail(params);
+      }
+    },
+    morePage: () => {
+      if (item.morePage === 'disabled') {
+        return;
+      } else if (item.morePage) {
+        navTo(item.morePage, {});
+      } else {
+        let modelId = 0;
+        let mainBodyColumnId : string|number|number[]|undefined = undefined;
+        switch (item.data.type) {
+          case 'commonContent':
+          case 'serializedApi': {
+            const params = doGetDynamicListDataParams(item.data);
+            modelId = params.modelId;
+            mainBodyColumnId = params.mainBodyColumnId;
+            break;
+          }
+          case 'detailContent':
+          case 'parentKey':
+          case 'request':
+            toast(`此配置选项不支持默认的更多页面跳转!`);
+            console.warn(`此配置选项不支持默认的更多页面跳转!`);
+            return;
+        }  
+        navCommonList({
+          title: item.title,
+          mainBodyColumnId: mainBodyColumnId,
+          modelId: modelId,
+          detailsPage: item.detailsPage,
+          dataSolve: item.dataSolve || [],
+          itemType: item.itemType,
+        })
+      }
+    },
+    data: useSimpleDataLoader(async () => {
+      let res : any[] = [];
+      const params = new GetContentListParams();
+      switch (item.data.type) {
+        case 'commonContent': {
+          params.setModelId(item.data.params.modelId);
+          if (item.data?.otherParams)
+            params.setSelfValues(item.data.otherParams);
+          if (item.data.params?.mainBodyColumnId)
+            params.setMainBodyColumnId(item.data.params.mainBodyColumnId);
+          res = (await CommonContent
+            .getContentList(params, 1, item.count || 4))
+            .list;
+          break;
         }
-      },
-      data: useSimpleDataLoader(async () => {
-        const params = new GetContentListParams();
-        if (item.data.type === 'serializedApi' && item.data.params?.mainBodyColumnId)
-          params.setMainBodyColumnId(item.data.params.mainBodyColumnId);
-        let res = (await (item.content as CommonContentApi)
-          .getContentList(params, 1, item.count || 4))
-          .list;
-        return resolveCommonContentSolveProps(res, item.dataSolve || []);;
-      }, false)
-    }
-  } else {
-    switch (item.content.type) {
-      case 'CommonCategoryBlock':
-        return {
-          ...item,
-          detailsPage: item.content.goDetail,
-          morePage: item.content.goList,
-          data: item.content.loader,
+        case 'serializedApi': {
+          if (item.data.params?.mainBodyColumnId)
+            params.setMainBodyColumnId(item.data.params.mainBodyColumnId);
+          if (item.data?.otherParams)
+            params.setSelfValues(item.data.otherParams);
+          res = (await CommonCategoryDynamicDataSerializedApi(item.data)
+            .getContentList(params, 1, item.count || 4))
+            .list;
+          break;
+        }
+        case 'detailContent': {
+          const data = item.data as IHomeCommonCategoryDynamicDataDetailContent;
+          res = [ await CommonContent.getContentDetail(data.params!.id, undefined, data.params!.modelId || undefined) ];
+          break;
         }
-      case 'detailContent':
-        return {
-          ...item,
-          detailsPage: defaultDetailsPageHandler,
-          morePage: () => {},
-          data: useSimpleDataLoader(async () => {
-            console.log(item);
-            const data = item.data as IHomeCommonCategoryDynamicDataDetailContent;
-            const res = await CommonContent.getContentDetail(data.params!.id, undefined, data.params!.modelId || undefined);
-            return resolveCommonContentSolveProps([res as any], item.dataSolve || []);;
-          }, false),
+        case 'parentKey': {
+          if (!props.parentData)
+            throw new Error('父级数据未设置');
+          res = props.parentData[item.data.key];
+          break;
         }
-      default: {
-        const block = useHomeCommonCategoryBlock({
-          ...item.content,
-          dataSolve: item.content.dataSolve ?? [],
-        }, false);
-        return {
-          ...item,
-          detailsPage: block.goDetail,
-          morePage: block.goList,
-          data: block.loader,
+        case 'request': {
+          res = (await CommonContent.request(
+            item.data.url, 
+            { 
+              page: 1,
+              pageSize: item.count || 4,
+              ...item.data.querys, 
+            }, 
+            {
+              method: item.data.method, 
+              data: item.data.otherParams,
+            },
+            '',
+            undefined,
+          )).data as unknown as any[];
+          break;
         }
+        default:
+          throw new Error(`未实现的动态数据接口 ${(item.data as any).type}`);
       }
-    }
+      return resolveCommonContentSolveProps(res, item.dataSolve || []);
+    }, false)
   }
 }));
 

+ 5 - 5
src/pages/article/data/CommonCategoryDetail.vue

@@ -137,7 +137,7 @@ import LoadingPage from '@/components/display/loading/LoadingPage.vue';
 import FlexCol from '@/components/layout/FlexCol.vue';
 import Result from '@/components/feedback/Result.vue';
 import Button from '@/components/basic/Button.vue';
-import { CommonCategoryListTabNestCategoryDataToContent, type IHomeCommonCategoryDefine, type IHomeCommonCategoryListTabNestCategoryItemDefine } from './CommonCategoryDefine';
+import { type IHomeCommonCategoryDefine, type IHomeCommonCategoryListTabNestCategoryItemDefine } from './CommonCategoryDefine';
 import { injectCommonCategory } from './CommonCategoryGlobalLoader';
 import { doLoadDynamicCategoryDataMergeTypeGetColumns } from './CommonCategoryDynamicData';
 import { formatError, StringUtils, waitTimeOut } from '@imengyu/imengyu-utils';
@@ -224,9 +224,7 @@ const tabRenderDefines = computed(() => {
               ...item,
               showTitle: item.showTitle !== false,
               title: item.text,
-              content: CommonCategoryListTabNestCategoryDataToContent(
-                item.data, item
-              ),
+              content: item.data,
               type: item.type as CategoryDefine['type'],
             }
           });
@@ -322,7 +320,7 @@ async function load(id: number, tabsArray: DetailTabPageTabsArray) {
   for (const tab of tabRenderDefinesArray.value) {
     const v = d[tab.key];
     let check = true
-    if (['intro','map'].includes(tab.type))
+    if (['intro'].includes(tab.type))
       check = true;
     else if (tab.type === 'audio')
       check = Boolean(d.audio);
@@ -330,6 +328,8 @@ async function load(id: number, tabsArray: DetailTabPageTabsArray) {
       check = Boolean(d.video);
     else if (tab.type === 'images')
       check = Boolean(d.images) && (d.images as string[]).length > 1;
+    else if (tab.type === 'map')
+      check = Boolean(d.latitude) && Boolean(d.longitude);
     else if (!v)
       check = false;
     else if (Array.isArray(v))

+ 24 - 2
src/pages/article/data/CommonCategoryDynamicData.ts

@@ -208,8 +208,6 @@ export async function doLoadDynamicListData(
       const params = new GetContentListParams();
       if (item.params?.mainBodyColumnId)
         params.setMainBodyColumnId(item.params.mainBodyColumnId);
-
-      console.log('aaaa', dropDownValues, dropdownDefines);
       return (await CommonCategoryDynamicDataSerializedApi(item).getContentList(
         params
         .setKeywords(keywords)
@@ -234,4 +232,28 @@ export async function doLoadDynamicListData(
         undefined,
       )).data;
   }
+}
+export function doGetDynamicListDataParams(data: IHomeCommonCategoryDynamicData) {
+  let modelId = 0;
+  let mainBodyColumnId : string|number|number[]|undefined = undefined;
+  switch (data.type) {
+    case 'commonContent':
+      modelId = data.params.modelId;
+      mainBodyColumnId = data.params.mainBodyColumnId;
+      break;
+    case 'serializedApi': {
+      const content = CommonCategoryDynamicDataSerializedApi(data);
+      modelId = content.modelId;
+      mainBodyColumnId = data.params?.mainBodyColumnId || content.mainBodyColumnId;
+      break;
+    }
+    case 'detailContent':
+    case 'parentKey':
+    case 'request':
+      break;
+  }  
+  return {
+    modelId,
+    mainBodyColumnId,
+  };
 }

+ 0 - 4
src/pages/article/data/CommonCategoryList.vue

@@ -13,7 +13,6 @@
       @error="errorMessage = $event"
     />
     <LoadingPage v-else />
-    <Footer text="我也是有底线的~" />
   </FlexCol>
 </template>
 
@@ -22,12 +21,9 @@ import { onMounted, ref, watch } from 'vue';
 import { injectCommonCategory } from './CommonCategoryGlobalLoader';
 import { type IHomeCommonCategoryDefine, type IHomeCommonCategoryListDefine } from './CommonCategoryDefine';
 import Result from '@/components/feedback/Result.vue';
-import CommonCategoryBlocks from './CommonCategoryBlocks.vue';
-import Footer from '@/components/display/Footer.vue';
 import FlexCol from '@/components/layout/FlexCol.vue';
 import LoadingPage from '@/components/display/loading/LoadingPage.vue';
 import Button from '@/components/basic/Button.vue';
-import { waitTimeOut } from '@imengyu/imengyu-utils';
 import CommonCategoryListBlock from './CommonCategoryListBlock.vue';
 
 /**

+ 14 - 5
src/pages/article/data/CommonCategoryListBlock.vue

@@ -11,25 +11,29 @@
     :dropDownNames="dropdownNames"
     :showListTabIds="showListTabIds"
     :detailsPage="detailsPage"
+    :detailsParams="detailsParams"
   >
     <template #list="{ tabId }">
       <CommonCategoryBlocks
         v-if="tabRenderDefines[tabId]?.type === 'nestCategory'" 
         :categoryDefine="tabRenderDefines[tabId].categoryDefine"
+        :parentData="currentParentData"
       />
       <CommonCategoryBlocks
         v-else-if="tabRenderDefines[tabId]?.type === 'list' && tabRenderDefines[tabId].preInsertCategorys?.length" 
         :categoryDefine="tabRenderDefines[tabId].categoryDefine"
+        :parentData="currentParentData"
       />
     </template>
   </CommonListPage>
+  <LoadingPage v-else />
 </template>
 
 <script setup lang="ts">
 import { computed, onMounted, ref, watch } from 'vue';
 import { navTo } from '@/components/utils/PageAction';
-import { doLoadDynamicCategoryDataMergeTypeGetColumns, doLoadDynamicDropdownData, doLoadDynamicListData } from './CommonCategoryDynamicData';
-import { CommonCategoryListTabNestCategoryDataToContent, type IHomeCommonCategoryDefine, type IHomeCommonCategoryListDefine, type IHomeCommonCategoryListTabDefine, type IHomeCommonCategoryListTabNestCategoryItemDefine } from './CommonCategoryDefine';
+import { doGetDynamicListDataParams, doLoadDynamicCategoryDataMergeTypeGetColumns, doLoadDynamicDropdownData, doLoadDynamicListData } from './CommonCategoryDynamicData';
+import { type IHomeCommonCategoryDefine, type IHomeCommonCategoryListDefine, type IHomeCommonCategoryListTabDefine, type IHomeCommonCategoryListTabNestCategoryItemDefine } from './CommonCategoryDefine';
 import { resolveCommonContentSolveProps } from '../common/CommonContent';
 import { waitTimeOut } from '@imengyu/imengyu-utils';
 import type { SimpleDropDownPickerItem } from '@/common/components/SimpleDropDownPicker.vue';
@@ -37,6 +41,7 @@ import type { CommonListPageProps, DropDownNames } from '../common/CommonListPag
 import type { CategoryDefine } from './CommonCategoryBlocks';
 import CommonListPage from '../common/CommonListPage.vue';
 import CommonCategoryBlocks from './CommonCategoryBlocks.vue';
+import LoadingPage from '@/components/display/loading/LoadingPage.vue';
 
 /**
  * 动态通用内容 - 通用列表页
@@ -141,9 +146,7 @@ const tabRenderDefines = computed(() => {
               ...item,
               showTitle: item.showTitle !== false,
               title: item.text,
-              content: CommonCategoryListTabNestCategoryDataToContent(
-                item.data, item
-              ),
+              content: item.data,
               type: item.type as CategoryDefine['type'],
             }
           });
@@ -213,6 +216,8 @@ const detailsPage = computed(() => {
   }
   return props.currentCommonCategoryContentDefine?.props.detailsPage || undefined;
 });
+const detailsParams = ref<Record<string, any>>({});
+const currentParentData = ref<any[]>([]);
 
 async function loadData(
   page: number, 
@@ -228,6 +233,9 @@ async function loadData(
     return { list: [], total: 0 };
   if (!tab.data) 
     throw new Error(`配置有误 tab:${tabSelect} 没有配置列表数据`);
+  detailsParams.value = {
+    ...(doGetDynamicListDataParams(tab.data)),
+  };
   const res = await doLoadDynamicListData(
     tab.data, 
     page, 
@@ -239,6 +247,7 @@ async function loadData(
   );
   if (res && tab.dataSolve)
     res.list = resolveCommonContentSolveProps(res.list, tab.dataSolve);
+  currentParentData.value = res?.list || [];
   return res;
 }
 </script>

+ 45 - 12
src/pages/article/data/DefaultCategory.json

@@ -28,7 +28,7 @@
             },
             {
               "title": "文化遗产说",
-              "icon": "http://mnwh.wenlvti.net/uploads/20260206/ebb8c0f75d49ddb6afed633bece0ca50.png",
+              "icon": "https://mnwh.wenlvti.net/uploads/20260206/ebb8c0f75d49ddb6afed633bece0ca50.png",
               "size": 50,
               "link": "/pages/article/data/list?pageConfigName=inhert",
               "style": "large-bg",
@@ -460,17 +460,17 @@
                 {
                   "text": "精品剧目",
                   "data": {
-                    "type": "commonContent",
+                    "type": "serializedApi",
+                    "name": "NewsIndexContent",
+                    "otherParams": {},
                     "params": {
-                      "mainBodyColumnId": 369,
-                      "modelId": 18
+                      "mainBodyColumnId": 369
                     }
                   },
-                  "dataSolve": [
-                    "common"
-                  ],
-                  "detailsPage": "byContent",
-                  "type": "article"
+                  "dataSolve": [],
+                  "detailsPage": "/pages/article/data/details?pageConfigName=songs-details",
+                  "type": "large-image",
+                  "morePage": "/pages/article/data/list?pageConfigName=best-drama"
                 },
                 {
                   "text": "非遗秀",
@@ -1143,7 +1143,7 @@
                   "type": "large-grid2"
                 }
               ],
-              "width": 250
+              "width": 230
             },
             {
               "text": "物质文化遗产",
@@ -1205,7 +1205,7 @@
                   "type": "StatsBlock"
                 }
               ],
-              "width": 250
+              "width": 230
             },
             {
               "text": "重点保护区域",
@@ -1238,7 +1238,7 @@
                   "type": "StatsBlock"
                 }
               ],
-              "width": 250
+              "width": 230
             },
             {
               "text": "世界文化遗产",
@@ -1996,6 +1996,39 @@
           ]
         }
       }
+    },
+    {
+      "name": "best-drama",
+      "title": "精品剧目",
+      "content": {
+        "type": "CommonList",
+        "props": {
+          "showTab": false,
+          "showSearch": true,
+          "showTotal": true,
+          "tabs": [
+            {
+              "text": "Root",
+              "type": "list",
+              "data": {
+                "type": "commonContent",
+                "params": {
+                  "modelId": 18,
+                  "mainBodyColumnId": 369
+                },
+                "otherParams": {
+                  "pid": "0"
+                }
+              },
+              "dataSolve": [
+                "common"
+              ]
+            }
+          ],
+          "itemType": "image-large",
+          "detailsPage": "/pages/article/data/details?pageConfigName=songs-details"
+        }
+      }
     }
   ]
 }

+ 1 - 31
src/pages/article/data/defines/List.ts

@@ -3,7 +3,6 @@
  * 列表定义
  */
 
-import type { HomeCommonCategoryBlockProps } from "../../common/CommonContent";
 import type { CommonListPageProps } from "../../common/CommonListPage.vue";
 import { CommonCategoryDynamicDataSerializedApi, type IHomeCommonCategoryDropdownDynamicData, type IHomeCommonCategoryDynamicData, type IHomeCommonCategoryDynamicDataCommonContent } from "../CommonCategoryDynamicData";
 
@@ -191,33 +190,4 @@ export interface IHomeCommonCategoryListTabNestCategoryItemDefine {
  */
 export type IHomeCommonCategoryListTabDefine = IHomeCommonCategoryListTabListDefine 
   | IHomeCommonCategoryListTabJumpDefine 
-  | IHomeCommonCategoryListTabNestCategoryDefine;
-
-export function CommonCategoryListTabNestCategoryDataToContent(
-  data: IHomeCommonCategoryDynamicData,
-  define: IHomeCommonCategoryListTabNestCategoryDefine['categorys'][0],
-) {
-  if (!data)
-    return null;
-  switch (data.type) {
-    case 'serializedApi':
-      return CommonCategoryDynamicDataSerializedApi(data);
-    case 'detailContent':
-      return data;
-    case 'parentKey':
-      throw new Error(`未实现的动态数据接口 ${data.type}`);
-    case 'request':
-      throw new Error(`未实现的动态数据接口 ${data.type}`);
-    case 'commonContent':
-      return {
-        title: define.text,
-        mainBodyColumnId: data.params.mainBodyColumnId,
-        modelId: data.params.modelId,
-        itemType: define.itemType,
-        detailsPage: define.detailsPage || 'byContent',
-        count: define.count,
-        params: (define.data as IHomeCommonCategoryDynamicDataCommonContent).otherParams || {},
-        dataSolve: define.dataSolve || [],
-      } as HomeCommonCategoryBlockProps;
-  }
-}
+  | IHomeCommonCategoryListTabNestCategoryDefine;

+ 1 - 1
src/pages/article/data/editor/subpart/PropsEditorTree.vue

@@ -2,7 +2,7 @@
   <div class="props-editor-tree">
     <a-form :labelCol="{ span: 6 }" size="small" class="props-form">
       <a-form-item label="页面 key">
-        <a-input v-model:value="props.page.name" disabled />
+        <a-input v-model:value="props.page.name" />
       </a-form-item>
       <a-form-item label="页面标题">
         <a-input v-model:value="props.page.title" />

+ 7 - 5
src/pages/article/details.vue

@@ -1,8 +1,8 @@
 <template>
   <FlexCol backgroundColor="background.page">
-    <FlexCol position="absolute" :top="0" :left="0" :right="0" :zIndex="100">
+    <FlexCol position="fixed" :top="0" :left="0" :right="0" :zIndex="100">
       <StatusBarSpace backgroundColor="transparent" />
-      <NavBar leftButton="back" :iconProps="{ color: 'white' }" textColor="white" />
+      <NavBar leftButton="back" :iconProps="{ color: 'white', innerStyle: { backgroundColor: 'rgba(0,0,0,0.2)' } }" textColor="white" />
     </FlexCol>
     <SimplePageContentLoader :loader="loader">
       <template v-if="loader.content.value">
@@ -63,6 +63,7 @@
               :title="item.title"
               :desc="item.desc"
               :wideImage="true"
+              :tags="(item.bottomTags as string[])"
               @click="goDetails(item.id)"
             />
           </view>
@@ -112,6 +113,7 @@ 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 { resolveCommonContentFormData } from "./common/CommonContent";
 
 const loader = useSimplePageContentLoader<
   GetContentDetailItem, 
@@ -120,7 +122,6 @@ const loader = useSimplePageContentLoader<
   if (!params)
     throw new Error("!params");
   const res = await NewsIndexContent.getContentDetail(params.id);
-  //console.log(res);
   uni.setNavigationBarTitle({ title: res.title });
   return res;
 });
@@ -163,11 +164,12 @@ const archiveInfo = computed(() => {
 const recommendListLoader = useSimpleDataLoader(async () => {
   if (!querys.value.modelId)
     return []
-  return (await CommonContent.getContentList(new GetContentListParams()
+  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);
+    .filter((p) => p.id !== querys.value.id)
+  return resolveCommonContentFormData(res);
 });
 
 function goArchive(id: number) {

+ 2 - 4
src/pages/home/home.vue

@@ -49,7 +49,7 @@
 import { computed } from 'vue';
 import { onShareTimeline, onShareAppMessage } from '@dcloudio/uni-app';
 import { navTo } from '@/components/utils/PageAction';
-import { CommonCategoryListTabNestCategoryDataToContent, type IHomeCommonCategoryDefine, type IHomeCommonCategoryHomeDefine } from '../article/data/CommonCategoryDefine';
+import { type IHomeCommonCategoryDefine, type IHomeCommonCategoryHomeDefine } from '../article/data/CommonCategoryDefine';
 import NImage from '@/components/basic/Image.vue';
 import HomeButton from '../parts/HomeButton.vue';
 import CommonCategoryBlocks from '../article/data/CommonCategoryBlocks.vue';
@@ -66,9 +66,7 @@ const categoryDefine = computed(() => props.pageContentDefine.props.categorys
       ...item,
       showTitle: item.showTitle !== false,
       title: item.text,
-      content: CommonCategoryListTabNestCategoryDataToContent(
-        item.data, item
-      ),
+      content: item.data,
       type: item.type as CategoryDefine['type'],
     }
   })

+ 51 - 3
src/pages/inhert/village/details.vue

@@ -121,14 +121,16 @@ import { ref, toRefs, type Ref } from 'vue';
 import { useLoadQuerys } from '@/common/composeabe/LoadQuerys';
 import { useSwiperImagePreview } from '@/common/composeabe/SwiperImagePreview';
 import { navTo } from '@/components/utils/PageAction';
-import { useSimpleDataLoader } from '@/common/composeabe/SimpleDataLoader';
-import { useHomeCommonCategoryBlock, type IHomeCommonCategoryBlock } from '@/pages/article/common/CommonContent';
+import { useSimpleDataLoader, type ISimpleDataLoader } from '@/common/composeabe/SimpleDataLoader';
 import ContentNote from '@/pages/parts/ContentNote.vue';
 import IntroBlock from '@/pages/article/common/IntroBlock.vue';
 import ImagesUrls from '@/common/config/ImagesUrls';
 import { onShareTimeline, onShareAppMessage } from '@dcloudio/uni-app';
 import Parse from '@/components/display/parse/Parse.vue';
 import Image from '@/components/basic/Image.vue';
+import type { GetContentListItem } from '@/api/CommonContent';
+import { navCommonList } from '@/pages/article/common/CommonContent';
+import CommonContent, { GetContentListParams } from '@/api/CommonContent';
 
 const EmptyImage = 'https://mncdn.wenlvti.net/app_static/minnan/EmptyImage.png';
 
@@ -138,7 +140,53 @@ interface TagDataItem {
   modelId?: number,
   mainBodyColumnId?: number,
 }
-interface TagDataRecommendItem extends TagDataItem, IHomeCommonCategoryBlock {
+interface TagDataRecommendItem extends TagDataItem {
+  loader: ISimpleDataLoader<GetContentListItem[], any>;
+  goDetail: (i: GetContentListItem) => void;
+  goList: () => void; 
+}
+
+function useHomeCommonCategoryBlock(p: {
+  title?: string,
+  type?: '',
+  mainBodyColumnId?: string|number|number[],
+  modelId?: number,
+  itemType?: string,
+  detailsPage: string,
+  count?: number,
+  params?: Record<string, any>
+}, loadWhenMounted = true) {
+  function goDetail(i: GetContentListItem) {
+    navTo(p.detailsPage, 
+    {
+      mainBodyColumnId: p.mainBodyColumnId,
+      modelId: p.modelId,
+      id: i.id,
+    }) 
+  }
+  function goList() {
+    navCommonList({
+      title: p.title,
+      mainBodyColumnId: typeof p.mainBodyColumnId == 'object' ? 
+        p.mainBodyColumnId.join(',') : 
+        p.mainBodyColumnId,
+      modelId: p.modelId,
+      itemType: p.itemType,
+      detailsPage: p.detailsPage,
+    }) 
+  }
+  const loader = useSimpleDataLoader(async () => {
+    return (await CommonContent.getContentList(new GetContentListParams().setSelfValues({
+      mainBodyColumnId: p.mainBodyColumnId,
+      modelId: p.modelId,
+      ...p.params,
+    }), 1, p.count ?? 4)).list;
+  }, loadWhenMounted);
+  return {
+    loader,
+    goDetail,
+    goList,
+  }
 }
 
 const center = ref([118.15723, 24.48147]);

+ 21 - 43
src/pages/user/contribute/list.vue

@@ -1,60 +1,38 @@
 <template>
-  <view class="d-flex flex-column bg-base" style="min-height:100vh">
-    <view class="p-3">
-      <SearchBar
-        v-model="searchText"
-        placeholder="搜一搜" 
-        @search="search"
-      />
-    </view>
-    <view class="d-flex flex-column p-3">
-      <Box2LineImageRightShadow 
-        v-for="item in listLoader.list.value"
-        :key="item.id" 
-        classNames="ml-2 mb-3"
-        titleColor="title-text"
-        :image="item.thumbnail || item.image"
-        :title="item.title"
-        :tags="item.keywords"
-        :desc="item.desc"
-        @click="goDetail(item.id)"
-      />
-    </view>
-    <SimplePageListLoader :loader="listLoader" />
-  </view>
+  <CommonListPage 
+    title="我的投稿"
+    showTotal
+    emptyText="您还没有投稿,欢迎去投稿"
+    detailsPage="custom"
+    :load="loadData" 
+    @goCustomDetails="goDetail"
+  />
 </template>
 
 <script setup lang="ts">
-import { GetContentListItem } from '@/api/CommonContent';
-import SimplePageListLoader from '@/common/components/SimplePageListLoader.vue';
-import { useSimplePageListLoader } from '@/common/composeabe/SimplePageListLoader';
-import { ref } from 'vue';
 import { navTo } from '@/components/utils/PageAction';
-import { onLoad } from '@dcloudio/uni-app';
 import ContributeApi from '@/api/user/ContributeApi';
-import Box2LineImageRightShadow from '@/pages/parts/Box2LineImageRightShadow.vue';
-import SearchBar from '@/components/form/SearchBar.vue';
+import CommonListPage from '@/pages/article/common/CommonListPage.vue';
 
-const searchText = ref('');
-const listLoader = useSimplePageListLoader<GetContentListItem>(
-  8, 
-  async (page, pageSize, params) => {
+async function loadData(
+  page: number, 
+  pageSize: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
   const list = await ContributeApi.getContributeList(page, pageSize);
   return {
     list,
     total: list.length,
   }
-});
-
-function goDetail(id: number) {
-  navTo('/pages/article/details', { id });
 }
-function search() {
-  listLoader.loadData(undefined, true);
+function goDetail(item: any, id: number) {
+  navTo('/pages/article/details', { 
+    id,
+    modelId: item.modelId, 
+    mainBodyColumnId: item.mainBodyColumnId 
+  });
 }
-onLoad(() => {
-  listLoader.loadData()
-})
 </script>
 
 <style lang="scss">