소스 검색

🎨 按要求调整栏目

快乐的梦鱼 5 일 전
부모
커밋
1d0cca8374

+ 6 - 3
src/pages/article/data/CommonCategoryDynamicData.ts

@@ -106,7 +106,10 @@ export interface IHomeCommonCategoryDynamicDataRequest {
   method: "OPTIONS" | "GET" | "HEAD" | "POST" | "PUT" | "DELETE",
   url: string,
   querys?: Record<string, any>,
-  params?: Record<string, any>,
+  /**
+   * 其他参数
+   */
+  otherParams?: Record<string, any>,
 }
 /**
  * 默认列表动态数据接口定义 - 从父级指定键内容
@@ -186,7 +189,7 @@ export async function doLoadDynamicListData(
         }) 
       , page, pageSize);
     case 'detailContent': {
-      const res = await CommonContent.getContentDetail(item.params.id, undefined, item.params.modelId || undefined);
+      const res = await CommonContent.getContentDetail(item.params.id, undefined, item.params.modelId || undefined, item.otherParams);
       return {
         list: page === 1 ? [res] : [],
         total: 1,
@@ -221,7 +224,7 @@ export async function doLoadDynamicListData(
         {
           method: item.method, 
           data: {
-            ...item.params,
+            ...item.otherParams,
             ...CommonCategorDynamicDropDownValuesToParams(dropDownValues, dropdownDefines || [])
           },
         },

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

@@ -24,7 +24,7 @@
             },
             {
               "title": "闽南新鲜事",
-              "icon": "https://mncdn.wenlvti.net/app_static/minnan/images/home/Button12.png",
+              "icon": "https://mncdn.wenlvti.net/app_static/minnan/images/home/Button4.png",
               "size": 50,
               "link": [
                 "/pages/article/data/list",
@@ -36,7 +36,7 @@
             },
             {
               "title": "遗产报你知",
-              "icon": "https://mncdn.wenlvti.net/app_static/minnan/images/home/Button13.png",
+              "icon": "https://mncdn.wenlvti.net/app_static/minnan/images/home/Button12.png",
               "size": 50,
               "link": [
                 "/pages/article/data/list",
@@ -225,7 +225,8 @@
                       "id": 8494,
                       "modelId": 14
                     }
-                  }
+                  },
+                  "showMore": false
                 },
                 {
                   "text": "闽南文化",
@@ -255,7 +256,7 @@
                   "dataSolve": [
                     "inheritor"
                   ],
-                  "detailsPage": "/pages/introduction/character/details",
+                  "detailsPage": "/pages/article/data/details?pageConfigName=inheritor-details",
                   "morePage": "/pages/article/data/list?pageConfigName=character",
                   "type": "",
                   "textLevel": "h3"
@@ -346,10 +347,14 @@
                   "data": {
                     "type": "commonContent",
                     "params": {
-                      "mainBodyColumnId": [
-                        385
-                      ],
-                      "modelId": 18
+                      "mainBodyColumnId": 374,
+                      "modelId": 18,
+                      "otherParams": {
+                        "pid": "0"
+                      }
+                    },
+                    "otherParams": {
+                      "pid": "0"
                     }
                   },
                   "morePage": "/pages/travel/fashion/list",
@@ -364,7 +369,13 @@
                       "mainBodyColumnId": [
                         375
                       ],
-                      "modelId": 18
+                      "modelId": 18,
+                      "otherParams": {
+                        "pid": "0"
+                      }
+                    },
+                    "otherParams": {
+                      "pid": "0"
                     }
                   },
                   "morePage": "/pages/travel/fashion/list",
@@ -1209,7 +1220,6 @@
                   ]
                 }
               },
-              "visible": false,
               "dataSolve": [
                 "form",
                 "common"
@@ -1606,7 +1616,8 @@
             {
               "text": "荣誉奖项",
               "type": "rich",
-              "key": "prize"
+              "key": "prize",
+              "width": 200
             },
             {
               "text": "非遗项目",
@@ -1630,7 +1641,8 @@
                     }
                   ]
                 }
-              }
+              },
+              "width": 200
             },
             {
               "text": "传习所",
@@ -1666,6 +1678,67 @@
       }
     },
     {
+      "name": "character-details",
+      "title": "历史人物详情页",
+      "content": {
+        "type": "Details",
+        "props": {
+          "introBlockDescs": [
+            {
+              "label": "年代",
+              "key": "age"
+            },
+            {
+              "label": "民族",
+              "key": "nation"
+            },
+            {
+              "label": "性别",
+              "key": "gender",
+              "map": {
+                "1": "男",
+                "2": "女"
+              }
+            },
+            {
+              "label": "出生日期",
+              "key": "dateBirth"
+            },
+            {
+              "label": "出生地区",
+              "key": "birthplace"
+            }
+          ],
+          "introBlocks": [],
+          "tabs": [
+            {
+              "text": "简介",
+              "type": "intro"
+            },
+            {
+              "text": "图片",
+              "type": "images",
+              "prefix": "以下照片由传承人提供"
+            },
+            {
+              "text": "视频",
+              "type": "video"
+            },
+            {
+              "text": "音频",
+              "type": "audio"
+            },
+            {
+              "text": "荣誉奖项",
+              "type": "rich",
+              "key": "prize",
+              "width": 200
+            }
+          ]
+        }
+      }
+    },
+    {
       "name": "songs-details",
       "title": "双歌赛详情页",
       "content": {

+ 2 - 2
src/pages/article/data/defines/List.ts

@@ -5,7 +5,7 @@
 
 import type { HomeCommonCategoryBlockProps } from "../../common/CommonContent";
 import type { CommonListPageProps } from "../../common/CommonListPage.vue";
-import { CommonCategoryDynamicDataSerializedApi, type IHomeCommonCategoryDropdownDynamicData, type IHomeCommonCategoryDynamicData } from "../CommonCategoryDynamicData";
+import { CommonCategoryDynamicDataSerializedApi, type IHomeCommonCategoryDropdownDynamicData, type IHomeCommonCategoryDynamicData, type IHomeCommonCategoryDynamicDataCommonContent } from "../CommonCategoryDynamicData";
 
 /**
  * 页面模板:列表定义
@@ -216,7 +216,7 @@ export function CommonCategoryListTabNestCategoryDataToContent(
         itemType: define.itemType,
         detailsPage: define.detailsPage || 'byContent',
         count: define.count,
-        params: define.params,
+        params: (define.data as IHomeCommonCategoryDynamicDataCommonContent).otherParams || {},
         dataSolve: define.dataSolve || [],
       } as HomeCommonCategoryBlockProps;
   }

+ 40 - 57
src/pages/article/data/editor/components/DynamicDataEditor.vue

@@ -28,6 +28,12 @@
             @change="(e: Event) => setMainBodyColumnId('commonContent', (e.target as HTMLInputElement)?.value)"
           />
         </a-form-item>
+        <a-form-item label="其他参数 (otherParams)">
+          <KeyValueEditor
+            :modelValue="(modelValue as IHomeCommonCategoryDynamicDataCommonContent)?.otherParams"
+            @update:modelValue="(v: Record<string, any>) => setOtherParams(v)"
+          />
+        </a-form-item>
       </template>
 
       <template v-else-if="currentType === 'detailContent'">
@@ -47,6 +53,12 @@
             @update:value="(v: number | undefined) => setDetailContent('modelId', v)"
           />
         </a-form-item>
+        <a-form-item label="其他参数 (otherParams)">
+          <KeyValueEditor
+            :modelValue="(modelValue as IHomeCommonCategoryDynamicDataCommonContent)?.otherParams"
+            @update:modelValue="(v: Record<string, any>) => setOtherParams(v)"
+          />
+        </a-form-item>
       </template>
 
       <template v-else-if="currentType === 'serializedApi'">
@@ -68,6 +80,12 @@
             @change="(e: Event) => setSerializedApiMainBodyColumnId((e.target as HTMLInputElement)?.value)"
           />
         </a-form-item>
+        <a-form-item label="其他参数 (otherParams)">
+          <KeyValueEditor
+            :modelValue="(modelValue as IHomeCommonCategoryDynamicDataSerializedApi)?.otherParams"
+            @update:modelValue="(v: Record<string, any>) => setOtherParams(v)"
+          />
+        </a-form-item>
       </template>
 
       <template v-else-if="currentType === 'request'">
@@ -87,28 +105,26 @@
           />
         </a-form-item>
         <a-form-item label="查询参数 (querys) JSON">
-          <a-input
-            :value="requestQuerysJson"
-            placeholder='{"key": "value"}'
-            :rows="2"
-            @change="(e: Event) => setRequestQuerys((e.target as HTMLInputElement)?.value)"
+          <KeyValueEditor
+            :modelValue="(modelValue as IHomeCommonCategoryDynamicDataRequest)?.querys"
+            @update:modelValue="(v: Record<string, any>) => setRequest('querys', v)"
           />
         </a-form-item>
         <a-form-item label="请求体参数 (params) JSON">
-          <a-input
-            :value="requestParamsJson"
-            placeholder='{"key": "value"}'
-            :rows="2"
-            @change="(e: Event) => setRequestParams((e.target as HTMLInputElement)?.value)"
+          <KeyValueEditor
+            :modelValue="(modelValue as IHomeCommonCategoryDynamicDataRequest)?.otherParams"
+            @update:modelValue="(v: Record<string, any>) => setRequest('otherParams', v)"
           />
         </a-form-item>
       </template>
+
+
     </a-form>
   </div>
 </template>
 
 <script setup lang="ts">
-import { computed, ref, watch } from 'vue';
+import { computed } from 'vue';
 import type {
   IHomeCommonCategoryDynamicData,
   IHomeCommonCategoryDynamicDataCommonContent,
@@ -117,6 +133,7 @@ import type {
   IHomeCommonCategoryDynamicDataDetailContent,
 } from '@/pages/article/data/CommonCategoryDynamicData';
 import { SerializedApiMap } from '@/pages/article/data/CommonCategoryDynamicData';
+import KeyValueEditor from './KeyValueEditor.vue';
 
 const props = defineProps<{
   modelValue?: IHomeCommonCategoryDynamicData | null;
@@ -179,32 +196,41 @@ function onTypeChange(type: 'commonContent' | 'serializedApi' | 'request') {
     emit('update:modelValue', {
       type: 'commonContent',
       params: { modelId: 1, mainBodyColumnId: undefined, typeId: undefined },
+      otherParams: {},
     });
   } else if (type === 'serializedApi') {
     emit('update:modelValue', {
       type: 'serializedApi',
       name: Object.keys(SerializedApiMap)[0] ?? 'ProjectsContent',
+      otherParams: {},
     });
   } else if (type === 'request') {
     emit('update:modelValue', {
       type: 'request',
       method: 'GET',
       url: '',
+      otherParams: {},
     });
   } else if (type === 'detailContent') {
     emit('update:modelValue', {
       type: 'detailContent',
       params: { id: 0, modelId: 0 },
+      otherParams: {},
     });
   }
 }
 
-function setCommonContent(key: 'modelId' | 'typeId', value: number | undefined) {
+function setCommonContent(key: 'modelId' | 'typeId'|'otherParams', value: number | Record<string, any> | undefined) {
   const cur = props.modelValue as IHomeCommonCategoryDynamicDataCommonContent | undefined;
   if (!cur || cur.type !== 'commonContent') return;
   const next = { ...cur, params: { ...cur.params, [key]: value } };
   emit('update:modelValue', next);
 }
+function setOtherParams(value: Record<string, any> | undefined) {
+  const cur = props.modelValue;
+  const next = { ...cur, otherParams: value } as IHomeCommonCategoryDynamicData ;
+  emit('update:modelValue', next);
+}
 
 function setMainBodyColumnId(source: 'commonContent' | 'serializedApi', input: string) {
   const parsed = parseMainBodyColumnId(input);
@@ -219,7 +245,7 @@ function setMainBodyColumnId(source: 'commonContent' | 'serializedApi', input: s
   }
 }
 
-function setSerializedApi(key: 'name', value: string) {
+function setSerializedApi(key: 'name'|'otherParams', value: any) {
   const cur = props.modelValue as IHomeCommonCategoryDynamicDataSerializedApi | undefined;
   if (!cur || cur.type !== 'serializedApi') return;
   emit('update:modelValue', { ...cur, [key]: value });
@@ -233,7 +259,7 @@ function setSerializedApiMainBodyColumnId(input: string) {
   emit('update:modelValue', { ...cur, params: Object.keys(params).length ? params : undefined });
 }
 
-function setRequest(key: 'method' | 'url', value: string) {
+function setRequest(key: 'method' | 'url'|'otherParams'|'querys', value: string|Record<string, any>) {
   const cur = props.modelValue as IHomeCommonCategoryDynamicDataRequest | undefined;
   if (!cur || cur.type !== 'request') return;
   emit('update:modelValue', { ...cur, [key]: value });
@@ -246,49 +272,6 @@ function setDetailContent(key: 'id' | 'modelId', value: number | undefined) {
   emit('update:modelValue', next);
 }
 
-const requestQuerysJson = computed(() => {
-  const cur = props.modelValue as IHomeCommonCategoryDynamicDataRequest | undefined;
-  if (!cur?.querys) return '';
-  try {
-    return typeof cur.querys === 'string' ? cur.querys : JSON.stringify(cur.querys, null, 2);
-  } catch {
-    return '';
-  }
-});
-
-const requestParamsJson = computed(() => {
-  const cur = props.modelValue as IHomeCommonCategoryDynamicDataRequest | undefined;
-  if (!cur?.params) return '';
-  try {
-    return typeof cur.params === 'string' ? cur.params : JSON.stringify(cur.params, null, 2);
-  } catch {
-    return '';
-  }
-});
-
-function setRequestQuerys(str: string) {
-  const cur = props.modelValue as IHomeCommonCategoryDynamicDataRequest | undefined;
-  if (!cur || cur.type !== 'request') return;
-  let querys: Record<string, any> | undefined;
-  try {
-    querys = str?.trim() ? JSON.parse(str) : undefined;
-  } catch {
-    return;
-  }
-  emit('update:modelValue', { ...cur, querys });
-}
-
-function setRequestParams(str: string) {
-  const cur = props.modelValue as IHomeCommonCategoryDynamicDataRequest | undefined;
-  if (!cur || cur.type !== 'request') return;
-  let params: Record<string, any> | undefined;
-  try {
-    params = str?.trim() ? JSON.parse(str) : undefined;
-  } catch {
-    return;
-  }
-  emit('update:modelValue', { ...cur, params });
-}
 </script>
 
 <style scoped>

+ 31 - 11
src/pages/article/data/editor/components/KeyValueEditor.vue

@@ -13,7 +13,7 @@
       <div class="key-value-container">
         <div
           v-for="item in localItems"
-          :key="item.key"
+          :key="item.ukey"
           class="key-value-item"
         >
           <a-input
@@ -43,6 +43,9 @@
           <plus-outlined /> 添加项
         </a-button>
       </div>
+      <a-button type="primary" block @click="save">
+        保存
+      </a-button>
     </a-modal>
   </div>
 </template>
@@ -51,6 +54,7 @@
 import { ref, computed, watch } from 'vue';
 import { PlusOutlined } from '@ant-design/icons-vue';
 import ValueEditor from './ValueEditor.vue';
+import { RandomUtils } from '@imengyu/imengyu-utils';
 
 const props = defineProps<{
   modelValue?: Record<string, any>;
@@ -71,6 +75,7 @@ const emit = defineEmits<{
 
 type LocalItem = {
   key: string;
+  ukey: string;
   value: any;
   type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'null';
 };
@@ -78,6 +83,15 @@ type LocalItem = {
 const modalVisible = ref(false);
 const localItems = ref<LocalItem[]>([]);
 
+function save() {
+  const newObj = localItems.value.reduce((acc, cur) => ({
+    ...acc,
+    [cur.key]: cur.value,
+  }), {} as Record<string, any>);
+  emit('update:modelValue', newObj);
+  modalVisible.value = false;
+}
+
 const objectPreview = computed(() => {
   return localItems.value.map((item) => {
     let value = '';
@@ -118,13 +132,16 @@ watch(
   (newValue) => {
     if (newValue) {
       localItems.value = Object.entries(newValue).map(([key, value]) => ({ 
-        key, 
+        key: key || '', 
+        ukey: RandomUtils.genNonDuplicateIDHEX(10),
         value,
         type: getType(value),
       }));
     } else {
       localItems.value = [];
     }
+    console.log('aaaa', newValue, localItems);
+    
   },
   { deep: true, immediate: true }
 );
@@ -139,17 +156,18 @@ const updateValue = () => {
 };
 
 // 获取一个可用的键
-const getUseableKey = (key: string) => {
-  if (!key) {
-    key = 'key';
+const getUseableKey = (item: LocalItem) => {
+  if (!item.key) {
+    item.key = 'key';
   }
   
-  let useableKey = key;
+  let useableKey = item.key;
   let suffix = 1;
   
+  const withoutSelfItems = localItems.value.filter((i) => i.ukey !== item.ukey);
   // 检查键是否已存在
-  while (localItems.value.some((item) => item.key === useableKey)) {
-    useableKey = `${key}${suffix}`;
+  while (withoutSelfItems.some((item) => item.key === useableKey)) {
+    useableKey = `${item.key}${suffix}`;
     suffix++;
   }
   
@@ -159,8 +177,8 @@ const getUseableKey = (key: string) => {
 // 更新键
 const updateKey = (item: LocalItem) => {
   // 检查是否有重复的key
-  if (localItems.value.some((i) => i.key === item.key)) {
-    item.key = getUseableKey(item.key);
+  if (localItems.value.filter((i) => i.key === item.key).length > 1) {
+    item.key = getUseableKey(item);
   }
 };
 
@@ -169,9 +187,10 @@ const addItem = () => {
   const template = props.defaultCreateTemplate || {
     key: `key${localItems.value.length + 1}`,
     value: '',
+    ukey: RandomUtils.genNonDuplicateIDHEX(10),
     type: 'string',
   };
-  template.key = getUseableKey(template.key);
+  template.key = getUseableKey(template);
   localItems.value.push(template);
   updateValue();
 };
@@ -193,6 +212,7 @@ const removeItem = (key: string) => {
 .key-value-container {
   width: 100%;
   max-height: 500px;
+  margin-bottom: 12px;
   overflow-y: auto;
 }