Bladeren bron

📦 按要求修改轮播图

快乐的梦鱼 1 maand geleden
bovenliggende
commit
214068e866

+ 4 - 2
src/App.vue

@@ -1,6 +1,7 @@
 <script setup lang="ts">
 import AppConfig, { isProd, isTestEnv } from '@/common/config/AppCofig'
 import { useAuthStore } from './store/auth'
+import { useAppConfiguration } from './api/system/useAppConfiguration';
 import { useAppInit } from './common/composeabe/AppInit';
 import { BugReporterAbstractionUniapp } from './common/BugReporter/impl/BugReporterAbstractionUniapp';
 import { IconUtils } from './components/basic/IconUtils';
@@ -15,14 +16,14 @@ import '@/common/style/icons';
 
 const authStore = useAuthStore();
 const { init } = useAppInit();
+const { loadAppConfiguration } = useAppConfiguration();
 const redirectThrottle = new MemoryTimeOut('RedirectThrottle', 50000);
 
-
 onLaunch(async () => {
   console.log('App Launch');
 
-  //加载字体
   loadFontFace();
+  await loadAppConfiguration();
 
   //加载登录信息
   const loginState = await authStore.loadLoginState();
@@ -80,6 +81,7 @@ function loadFontFace() {
   });
 }
 
+
 configAppTheme();
 
 IconUtils.loadDefaultIcons('https://mncdn.wenlvti.net/app_static/xiangyuan/data/DefaultIcon.json');

+ 85 - 0
src/api/RequestModules.ts

@@ -166,4 +166,89 @@ export class TencentMengyuServerRequestModule<T extends DataModel> extends BaseA
       }
     };
   }
+}
+
+/**
+ * 更新服务请求模块
+ */
+export class UpdateServerRequestModule<T extends DataModel> extends BaseAppServerRequestModule<T> {
+  constructor() {
+    super("https://update-server1.imengyu.top");
+    this.config.requestInterceptor = (url, req) => {
+      if (!req.headers)
+        req.headers = {};
+      req.headers['Authorization'] = JSON.stringify({
+        "apiKey":"MQQDGbn8QfFJ7kStNtkxwifHP4sBTSDd",
+        "apiSecret":"3BNAdR7NXGwfiRmQZkRcRM8PsyHPeBmaay2k2F4TXhGEziXSJ3ceEtH2ApfHsMhR"
+      });
+      return { newUrl: url, newReq: req };
+    };
+    this.config.responseDataHandler = async function responseDataHandler<T extends DataModel>(response: RequestResponse, req: RequestOptions, resultModelClass: NewDataModel | undefined, instance: RequestCoreInstance<T>, apiInfo: RequestApiInfoStruct): Promise<RequestApiResult<T>> {
+      const method = req.method || 'GET';
+      try {
+        const json = await response.json();
+        if (response.ok) {
+          if (!json) {
+            throw new RequestApiError(
+              'businessError',
+              '后端未返回数据',
+              '',
+              response.status,
+              null,
+              null,
+              response.headers,
+              apiInfo
+            );
+          }
+          if (!json.success)
+            throw new RequestApiError(
+              'businessError',
+              json.message,
+              json.code.toString(),
+              json.code,
+              json,
+              json,
+              response.headers,
+              apiInfo
+            );
+          
+          return new RequestApiResult(
+            resultModelClass ?? instance.config.modelClassCreator,
+            json?.code || response.status,
+            json.message,
+            json.data,
+            json,
+            response.headers,
+            apiInfo
+          );
+        }
+        else {
+          throw json;
+        }
+
+      } catch (err) {
+        if (err instanceof RequestApiError) {
+          throw response;
+        }
+        //错误统一处理
+        return new Promise<RequestApiResult<T>>((resolve, reject) => {
+          defaultResponseDataHandlerCatch(method, req, response, null, err as any, apiInfo, response.url, reject, instance);
+        });
+      }
+    };
+  }
+
+  private static readonly DEVICE_UID_KEY = 'deviceUid';
+  private uid = '';
+
+  getDeviceUid() {
+    if (!this.uid) {
+      this.uid = uni.getStorageSync(UpdateServerRequestModule.DEVICE_UID_KEY);
+      if (!this.uid) {
+        this.uid = RandomUtils.genNonDuplicateID(20);
+        uni.setStorageSync(UpdateServerRequestModule.DEVICE_UID_KEY, this.uid);
+      }
+    }
+    return this.uid;
+  }
 }

+ 49 - 0
src/api/system/ConfigurationApi.ts

@@ -0,0 +1,49 @@
+import { UpdateServerRequestModule } from '@/api/RequestModules';
+import { LogUtils } from '@imengyu/imengyu-utils';
+import { DataModel } from '@imengyu/js-request-transform';
+import DefaultConfiguration from './DefaultConfiguration.json';
+
+export const CommonConfigurationConfig = {
+  /**
+   * 应用id
+   */
+  appId: 4,
+  appConfigId: 14,
+}
+
+export interface IConfigurationItem {
+  banners: {
+    homeTop: string;
+    homeTitle: string;
+    home: string[];
+    dig: string[];
+    discover: string[];
+  }
+}
+
+export class ConfigurationApi extends UpdateServerRequestModule<DataModel> {
+
+  constructor() {
+    super();
+  }
+
+  /**
+   * 获取当前配置,有缓存,会根据激活的历史版本获取对应配置
+   * @returns 
+   */
+  async getConfig() {
+    try {
+      return (await this.get<{
+        data: IConfigurationItem
+      }>('/app-configuration-get', '获取配置', {
+        name: CommonConfigurationConfig.appConfigId,
+        appId: CommonConfigurationConfig.appId,
+        })).data!.data;
+    } catch (error) {
+      LogUtils.printLog("ConfigurationApi", 'error', '获取配置失败,使用默认配置', error);
+      return DefaultConfiguration as IConfigurationItem;
+    }
+  }
+}
+
+export default new ConfigurationApi();

+ 15 - 0
src/api/system/DefaultConfiguration.json

@@ -0,0 +1,15 @@
+{
+  "banners": {
+    "homeTop": "https://xy.wenlvti.net/app_static/images/home/BannerHomeNew.png",
+    "homeTitle": "https://xy.wenlvti.net/app_static/images/home/BannerHomeTitle.png",
+    "home": [
+      "https://xy.wenlvti.net/app_static/images/banner/Home.jpg"
+    ],
+    "dig": [
+      "https://xy.wenlvti.net/app_static/images/banner/Dig.jpg"
+    ],
+    "discover": [
+      "https://xy.wenlvti.net/app_static/images/banner/Discover.jpg"
+    ]
+  }
+}

+ 29 - 0
src/api/system/useAppConfiguration.ts

@@ -0,0 +1,29 @@
+import { LogUtils } from "@imengyu/imengyu-utils";
+import { inject, provide, ref, type Ref } from "vue";
+import ConfigurationApi, { type IConfigurationItem } from "./ConfigurationApi";
+
+export const APP_CONFIGURATION_KEY = Symbol('APP_CONFIGURATION_KEY');
+
+const TAG = 'useAppConfiguration';
+
+export function useAppConfiguration() {
+  const appConfiguration = ref<IConfigurationItem | null>(null);
+
+  async function loadAppConfiguration() {
+    //获取配置
+    const config = await ConfigurationApi.getConfig();
+    LogUtils.printLog(TAG, 'info', '获取配置', config);
+    appConfiguration.value = config;
+  }
+
+  provide(APP_CONFIGURATION_KEY, appConfiguration);
+
+  return {
+    loadAppConfiguration,
+    appConfiguration,
+  };
+}
+
+export function injectAppConfiguration() {
+  return inject(APP_CONFIGURATION_KEY) as Ref<IConfigurationItem | null>;
+}

+ 28 - 4
src/common/components/parts/ImageSwiper.vue

@@ -7,7 +7,10 @@
     :interval="2000"
     :duration="1000"
     :style="{
-      height: `${height}rpx`,
+      height: themeContext.resolveThemeSize(height),
+      width: themeContext.resolveThemeSize(width),
+      borderRadius: themeContext.resolveThemeSize(radius),
+      ...innerStyle,
     }"
   >
     <swiper-item v-for="(item, key) in images" :key="key">
@@ -16,11 +19,18 @@
         :style="{
           backgroundImage: `url(${item})`,
           backgroundSize: 'cover',
+          height: themeContext.resolveThemeSize(height),
+          width: themeContext.resolveThemeSize(width),
+          borderRadius: themeContext.resolveThemeSize(radius),
         }"
       >
         <image
           :src="item"
-          :style="{ width: '100%', borderRadius: '20rpx' }"
+          :style="{
+            borderRadius: themeContext.resolveThemeSize(radius),
+            height: themeContext.resolveThemeSize(height),
+            width: themeContext.resolveThemeSize(width),
+          }"
           mode="aspectFit"
           @click="onPreviewImage(key)"
         />
@@ -31,6 +41,7 @@
 
 <script setup lang="ts">
 import { useSwiperImagePreview } from '@/common/composeabe/SwiperImagePreview';
+import { useTheme } from '@/components/theme/ThemeDefine';
 import type { PropType } from 'vue';
 
 const props = defineProps({
@@ -39,12 +50,25 @@ const props = defineProps({
     default: () => [],
   },
   height: {
-    type: Number as PropType<number>,
-    default: 400,
+    type:  [String, Number],
+    default: undefined,
+  },
+  width: {
+    type: [String, Number],
+    default: 16,
+  },
+  radius: {
+    type: [String, Number],
+    default: 16,
+  },
+  innerStyle: {
+    type: Object,
+    default: () => ({}),
   },
 })
 
 const { onPreviewImage } = useSwiperImagePreview(() => props.images || [])
+const themeContext = useTheme();
 
 </script>
 

+ 8 - 5
src/pages/home/dig.vue

@@ -2,14 +2,14 @@
   <FlexCol>
     <FlexCol :padding="30">
       <HomeLargeTitle title="挖掘" />
-      <Image 
-        mode="aspectFill" 
-        src="https://xy.wenlvti.net/app_static/images/dig/IntrodBanner.png"
+      <ImageSwiper
+        :images="appConfiguration?.banners.dig"
         width="100%"
-        :height="300"
+        :height="400"
         radius="radius.md"
         :innerStyle="{
           border: '1px solid #fff',
+          overflow: 'hidden',
         }"
       />
       <HomeTitle title="我的村社" />
@@ -119,6 +119,8 @@ import { navTo } from '@/components/utils/PageAction';
 import { useAuthStore } from '@/store/auth';
 import { useCollectStore } from '@/store/collect';
 import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
+import { useStorageVar } from '@/components/composeabe/StorageVar';
+import { injectAppConfiguration } from '@/api/system/useAppConfiguration';
 import VillageApi, { VillageListItem } from '@/api/inhert/VillageApi';
 import RequireLogin from '@/common/components/RequireLogin.vue';
 import SimplePageContentLoader from '@/components/loader/SimplePageContentLoader.vue';
@@ -138,11 +140,12 @@ import FrameButton from '@/common/components/FrameButton.vue';
 import CommonDivider from '@/common/components/CommonDivider.vue';
 import Touchable from '@/components/feedback/Touchable.vue';
 import Icon from '@/components/basic/Icon.vue';
-import { useStorageVar } from '@/components/composeabe/StorageVar';
 import BackgroundBox from '@/components/display/block/BackgroundBox.vue';
+import ImageSwiper from '@/common/components/parts/ImageSwiper.vue';
 
 const authStore = useAuthStore();
 const collectStore = useCollectStore();
+const appConfiguration = injectAppConfiguration();
 const { value: currentCity } = useStorageVar('currentCityName', '');
 
 const notVolunteerError = ref(false);

+ 8 - 4
src/pages/home/discover/index.vue

@@ -1,14 +1,14 @@
 <template>
   <FlexCol :gap="20" :padding="30">
     <HomeLargeTitle title="发现" />
-    <Image
-      mode="aspectFill" 
-      src="https://xy.wenlvti.net/app_static/images/dig/IntrodBanner.png"
+    <ImageSwiper
+      :images="appConfiguration?.banners.discover"
       width="100%"
-      :height="300"
+      :height="400"
       radius="radius.md"
       :innerStyle="{
         border: '1px solid #fff',
+        overflow: 'hidden',
       }"
     />
     
@@ -54,6 +54,7 @@
 <script setup lang="ts">
 import { navTo } from '@/components/utils/PageAction';
 import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
+import { injectAppConfiguration } from '@/api/system/useAppConfiguration';
 import SimplePageContentLoader from '@/components/loader/SimplePageContentLoader.vue';
 import Loadmore from '@/components/display/loading/Loadmore.vue';
 import FlexCol from '@/components/layout/FlexCol.vue';
@@ -66,6 +67,9 @@ import HomeLargeTitle from '@/common/components/parts/HomeLargeTitle.vue';
 import HomeTitle from '@/common/components/parts/HomeTitle.vue';
 import ImageBlock3 from '@/components/display/block/ImageBlock3.vue';
 import CommonContent, { GetContentListItem, GetContentListParams } from '@/api/CommonContent';
+import ImageSwiper from '@/common/components/parts/ImageSwiper.vue';
+
+const appConfiguration = injectAppConfiguration();
 
 const discoverLoader = useSimpleDataLoader(async () => {
   return (await CommonContent.getContentList(new GetContentListParams()

+ 12 - 9
src/pages/home/index.vue

@@ -2,7 +2,7 @@
   <FlexCol>
     <FlexCol :gap="20" :padding="[30,30,0,30]" :innerStyle="{
       marginTop: '-130px',
-      backgroundImage: 'url(https://xy.wenlvti.net/app_static/images/home/BannerHomeNew.png)',
+      backgroundImage: `url(${appConfiguration?.banners.homeTop})`,
       backgroundSize: '100% auto',
       backgroundRepeat: 'no-repeat',
       backgroundPosition: 'top center',
@@ -18,7 +18,7 @@
             :text="currentCity"
           />
           <Image
-            src="https://xy.wenlvti.net/app_static/images/home/BannerHomeTitle.png"
+            :src="appConfiguration?.banners.homeTitle"
             :width="140"
             :height="75"
           />
@@ -38,14 +38,14 @@
           }" />
           <Button icon="ai-thinking" @click="handleGoAI" text="问AI" />
         </FlexRow>
-        <Image 
-          src="https://xy.wenlvti.net/app_static/images/home/BannerIndex.png" 
-          width="700rpx" 
-          height="200px"
-          mode="aspectFit" 
+        <ImageSwiper 
+          :images="appConfiguration?.banners.home"
+          :height="460"
+          :width="700"
+          radius="radius.md"
           :innerStyle="{
-            border: '2px solid #fff',
-            borderRadius: '20rpx',
+            border: '1px solid #fff',
+            overflow: 'hidden',
             clipPath: 'ellipse(100% 90% at 50% 0%)'
           }"
         />
@@ -227,6 +227,8 @@ import MemoryTimeOut from '@/components/composeabe/MemoryTimeOut';
 import Touchable from '@/components/feedback/Touchable.vue';
 import Icon from '@/components/basic/Icon.vue';
 import Text from '@/components/basic/Text.vue';
+import { injectAppConfiguration } from '@/api/system/useAppConfiguration';
+import ImageSwiper from '@/common/components/parts/ImageSwiper.vue';
 
 const emit = defineEmits(['goVillage']);
 const { onPublishSuccess } = useOfficialAccount();
@@ -240,6 +242,7 @@ const showCityPopup = ref(false);
 const showMyFollowPopup = ref(false);
 const introClamTipRef = ref();
 const introClamTipTimeout = new MemoryTimeOut('IntroClamTip', 1000 * 3600 * 30);//30h
+const appConfiguration = injectAppConfiguration();
 
 const currentRegion = ref<number | null>(null);
 const { value: currentCity } = useStorageVar('currentCityName', '');