Преглед изворни кода

📦 对接分享好友奖励记录接口

快乐的梦鱼 пре 3 недеља
родитељ
комит
367145e795

+ 67 - 0
src/api/light/FollowVillageApi.ts

@@ -37,6 +37,33 @@ export class FollowedUserListItem extends DataModel<FollowedUserListItem> {
   jointime = new Date();
 }
 
+
+
+export class ShareRewardItem extends DataModel<ShareRewardItem> {
+  constructor() {
+    super(ShareRewardItem, '分享奖励');
+    this.setNameMapperCase('Camel', 'Snake');
+    this._afterSolveServer = (data) => { 
+      this.name = (this.volunteerName || this.nickname) as string;
+      if (this.followId && this.villageName)
+        this.desc = `应您邀请关注了${this.villageName}`;
+      else if (this.villageVolunteerId && this.villageName)
+        this.desc = `应您邀请成为了${this.villageName}志愿者`;
+      else
+        this.desc = `应您邀请加入亮乡源`;
+    }
+  }
+
+  id!: number;
+  avatar = '';
+  name = '';
+  desc = '';
+  points = 0;
+  rewardWater = 0;
+  rewardLight = 0;
+  rewardFruit = 0;
+}
+
 export class FollowVillageApi extends AppServerRequestModule<DataModel> {
   constructor() {
     super();
@@ -128,6 +155,46 @@ export class FollowVillageApi extends AppServerRequestModule<DataModel> {
       ),
     };
   }
+
+  
+
+  /** 分享奖励列表 */
+  async getShareRewardList(options?: {
+    page?: number;
+    pageSize?: number;
+    /**
+     * 分享奖励类型
+        user=邀请注册用户,
+        claim=邀请认领,
+        follow=邀请关注
+     */
+    type: string;
+  }) {
+    const res = await this.post<{
+      total: number;
+      per_page?: number;
+      current_page?: number;
+      last_page?: number;
+      data: any[];
+    }>(
+      '/user/inviteList',
+      '分享奖励列表',
+      {
+        page: options?.page,
+        pageSize: options?.pageSize,
+        type: options?.type,
+      },
+    );
+    return {
+      total: res.requireData().total ?? 0,
+      list: transformArrayDataModel<ShareRewardItem>(
+        ShareRewardItem,
+        transformSomeToArray(res.requireData().data),
+        '分享奖励',
+        true,
+      ),
+    }
+  }
 }
 
 export default new FollowVillageApi();

+ 0 - 40
src/api/light/TreeApi.ts

@@ -509,22 +509,6 @@ export class UpgradeOrderConfirm extends DataModel<UpgradeOrderConfirm> {
   };
 }
 
-export class ShareRewardItem extends DataModel<ShareRewardItem> {
-  constructor() {
-    super(ShareRewardItem, '分享奖励');
-    this.setNameMapperCase('Camel', 'Snake');
-  }
-
-  id!: number;
-  image = '';
-  name = '';
-  desc = '';
-  points = 0;
-  rewardWater = 0;
-  rewardLight = 0;
-  rewardFruit = 0;
-}
-
 type GrowthLogSearch = {
   page?: number;
   pageSize?: number;
@@ -981,30 +965,6 @@ export class TreeApi extends AppServerRequestModule<DataModel> {
     return transformDataModel<FruitDepositOrderConfirm>(FruitDepositOrderConfirm, res.requireData());
   }
 
-  /** 分享奖励列表 */
-  async getShareRewardList(options?: {
-    page?: number;
-    pageSize?: number;
-    keywords?: string;
-    villageId?: number;
-  }) {
-    const res = await this.post<PagedGrowthResponse>(
-      '/village/growth/shareRewardList',
-      '分享奖励列表',
-      {
-        page: options?.page,
-        pageSize: options?.pageSize,
-        keywords: options?.keywords,
-        village_id: options?.villageId,
-      },
-    );
-    return this.parsePagedList<ShareRewardItem>(
-      ShareRewardItem,
-      res.requireData(),
-      '分享奖励',
-    );
-  }
-
 }
 
 export default new TreeApi();

+ 6 - 1
src/api/system/ConfigurationApi.ts

@@ -14,7 +14,10 @@ export const CommonConfigurationConfig = {
 
 export interface IBannerItem {
   height: number;
-  images: string[];
+  images: string[]|{
+    image: string,
+    url: string,
+  }[];
 }
 export interface IConfigurationItem {
   banners: {
@@ -26,6 +29,8 @@ export interface IConfigurationItem {
       innerStyle?: Record<string, unknown>;
     };
     home: IBannerItem;
+    userAd: IBannerItem;
+    shareReward: IBannerItem;
     dig: IBannerItem;
     discover: IBannerItem;
   },

+ 9 - 1
src/common/components/parts/ImageSwiper.vue

@@ -31,7 +31,7 @@
             height: themeContext.resolveThemeSize(height),
             width: themeContext.resolveThemeSize(width),
           }"
-          mode="aspectFit"
+          :mode="mode"
           @click="onPreviewImage(key)"
         />
       </view>
@@ -53,6 +53,14 @@ const props = defineProps({
     })[]>,
     default: () => [],
   },
+  links: {
+    type: Array as PropType<string[]>,
+    default: () => [],
+  },
+  mode: {
+    type: String,
+    default: 'aspectFit',
+  },
   height: {
     type:  [String, Number],
     default: undefined,

+ 7 - 5
src/components/basic/Icon.vue

@@ -25,7 +25,7 @@
   <!-- #endif -->
   <!-- #ifndef H5 --> 
   <image
-    v-else-if="iconData.type == 'svg' && style.color && iconData.rawSvg"
+    v-else-if="iconData.type == 'svg' && iconData.rawSvg && style.color"
     :style="style"
     :class="innerClass"
     :src="IconUtils.getColoredSvg(iconData.rawSvg, style.color)"
@@ -124,17 +124,19 @@ const iconData = computed(() => {
 });
 const style = computed(() => {
   const size = theme.resolveThemeSize(props.size);
+  const color = theme.resolveThemeColor(props.color, 'text.content');
+  
   return {
     flexShrink: 0,
     fontSize: size,
     fontFamily: iconData.value.fontFamily || 'iconfont',
-    width: size,
-    height: size,
-    color: theme.resolveThemeColor(props.color, 'text.content'),
-    fill: theme.resolveThemeColor(props.color, 'text.content'),
     transform: props.rotate ? `rotate(${props.rotate}deg)` : undefined,
     overflow: 'visible',
     ...props.innerStyle,
+    color: color,
+    fill: color,
+    width: size,
+    height: size,
   };
 });
 

+ 3 - 3
src/components/theme/ThemeDefine.ts

@@ -116,14 +116,14 @@ export function useTheme() {
   function resolveThemeColor(inValue?: string, defaultValue?: string) : string|undefined {    
     if (isSpecialColor(inValue))
       return inValue;
+    if (inValue && (inValue.startsWith('#') || inValue.startsWith('rgb')))
+      return inValue;    
     if (inValue === undefined)
       inValue = defaultValue;
     else
       defaultValue = resolveThemeColor(defaultValue);
     if (inValue === undefined)
-      return undefined;
-    if (inValue.startsWith('#') || inValue.startsWith('rgb'))
-      return inValue;     
+      return undefined; 
     return getColor(inValue, defaultValue);
   }
   function resolveThemeSizes<T extends Record<string, string|number>>(defaults: T) : Record<string, string|number> {

+ 44 - 4
src/pages/home/village/task/share-reward.vue

@@ -1,6 +1,17 @@
 <template>
   <CommonTopBanner title="分享好友奖励">
     <FlexCol padding="padding.md">
+      <ImageSwiper
+        :images="appConfig.banners.shareReward?.images || []"
+        :height="appConfig.banners.shareReward?.height || 0"
+        :width="710"
+        radius="radius.md"
+      />
+      <Tabs 
+        v-model:currentIndex="recommendTabCurrent"
+        :tabs="recommendTabs"
+        :width="710"
+      />
       <SimplePageListLoader :loader="listLoader">
         <FlexCol gap="gap.md">
           <BoxMid
@@ -19,7 +30,7 @@
               align="center"
             >
               <FlexRow gap="gap.md" align="center">
-                <Icon :icon="item.image || 'space'" :size="100" />
+                <Avatar :src="item.avatar || 'space'" :size="100" />
                 <Width :size="5" />
                 <FlexCol gap="gap.md">
                   <Text fontConfig="lightImportantTitle" fontFamily="SongtiSCBlack">{{ item.name }}</Text>
@@ -40,27 +51,56 @@
 </template>
 
 <script setup lang="ts">
+import { ref, watch } from 'vue';
 import { useSimplePageListLoader } from '@/components/composeabe/loader/SimplePageListLoader';
+import { injectAppConfiguration } from '@/api/system/useAppConfiguration';
 import SimplePageListLoader from '@/components/loader/SimplePageListLoader.vue';
 import FlexCol from '@/components/layout/FlexCol.vue';
 import Text from '@/components/basic/Text.vue';
 import CommonTopBanner from '@/common/components/CommonTopBanner.vue';
-import TreeApi from '@/api/light/TreeApi';
+import FollowVillageApi from '@/api/light/FollowVillageApi';
 import BoxMid from '@/common/components/box/BoxMid.vue';
 import Touchable from '@/components/feedback/Touchable.vue';
 import FlexRow from '@/components/layout/FlexRow.vue';
 import Button from '@/components/basic/Button.vue';
-import Icon from '@/components/basic/Icon.vue';
 import Width from '@/components/layout/space/Width.vue';
+import ImageSwiper from '@/common/components/parts/ImageSwiper.vue';
+import Tabs from '@/components/nav/Tabs.vue';
+import Avatar from '@/components/display/Avatar.vue';
 
+const appConfig = injectAppConfiguration();
+const recommendTabCurrent = ref(0);
+const recommendTabs = ref([
+  {
+    text: '新用户',
+    value: 0,
+    type: 'user',
+  },
+  {
+    text: '新志愿者',
+    value: 1,
+    type: 'claim',
+  },
+  {
+    text: '新关注',
+    value: 2,
+    type: 'follow',
+  },
+]);
 const listLoader = useSimplePageListLoader(20, async (page, pageSize) => {
-  const res = await TreeApi.getShareRewardList({
+  const type = recommendTabs.value[recommendTabCurrent.value].type;
+  const res = await FollowVillageApi.getShareRewardList({
     page,
     pageSize,
+    type,
   });
   return {
     list: res.list,
     total: res.total,
   };
 });
+
+watch(() => recommendTabCurrent.value, () => {
+  listLoader.reload();
+});
 </script>

+ 14 - 4
src/pages/user/index.vue

@@ -65,6 +65,14 @@
       </FlexCol>
     </BoxMid>
 
+    <ImageSwiper
+      :images="appConfig.banners.userAd?.images || []"
+      :height="appConfig.banners.userAd?.height || 0"
+      :width="690"
+      mode="aspectFill"
+      radius="radius.md"
+    />
+
     <ProvideVar :vars="{
       CellBackground: 'background.tertiary',
       CellBottomBorder: false,
@@ -73,9 +81,9 @@
         <Cell v-if="userInfo" icon="https://xy.wenlvti.net/app_static/images/mine/IconMyArticle.png" title="我的投稿" showArrow touchable @click="navTo('/pages/dig/forms/submits', { 
           villageVolunteerId: volunteerInfo?.id || 0 
         })" />
-        <Cell icon="https://xy.wenlvti.net/app_static/images/mine/IconMyRecord.png" title="赐福记录" showArrow touchable @click="requireLogin(() => navTo('/pages/home/village/bless/my-orders'), '登录后查看我的福泽记录哦')" />
-        <Cell icon="share" :iconProps="{ color: '#833e27' }" title="分享记录" showArrow touchable @click="navTo('/pages/home/village/task/share-reward')" />
-        <Cell icon="https://xy.wenlvti.net/app_static/images/mine/IconMyReward.png" title="兑换记录" showArrow touchable @click="goStoreList" />
+        <Cell v-if="userInfo" icon="https://xy.wenlvti.net/app_static/images/mine/IconMyRecord.png" title="赐福记录" showArrow touchable @click="requireLogin(() => navTo('/pages/home/village/bless/my-orders'), '登录后查看我的福泽记录哦')" />
+        <Cell v-if="userInfo" icon="share" :iconProps="{ color: '#833e27' }" title="邀请记录" showArrow touchable @click="navTo('/pages/home/village/task/share-reward')" />
+        <Cell v-if="userInfo" icon="https://xy.wenlvti.net/app_static/images/mine/IconMyReward.png" title="兑换记录" showArrow touchable @click="goStoreList" />
         <Cell icon="https://xy.wenlvti.net/app_static/images/mine/IconAbout.png" title="关于我们" showArrow touchable @click="navTo('/pages/home/about/about')" />
         <button open-type="contact" class="remove-button-style">
           <Cell icon="https://xy.wenlvti.net/app_static/images/mine/IconContract.png" title="联系客服" showArrow touchable />
@@ -94,7 +102,7 @@ import { navTo } from '@/components/utils/PageAction';
 import { confirm } from '@/components/dialog/CommonRoot';
 import { useAuthStore } from '@/store/auth';
 import { useRequireLogin } from '@/common/composeabe/RequireLogin';
-import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
+import { injectAppConfiguration } from '@/api/system/useAppConfiguration';
 import { useWebPassToken } from '../article/web/webPassToken';
 import { useVolunteerInfo } from '../home/village/composeabe/VolunteerInfo';
 import CellGroup from '@/components/basic/CellGroup.vue';
@@ -117,8 +125,10 @@ import BoxMid from '@/common/components/box/BoxMid.vue';
 import FrameButton from '@/common/components/FrameButton.vue';
 import Width from '@/components/layout/space/Width.vue';
 import Height from '@/components/layout/space/Height.vue';
+import ImageSwiper from '@/common/components/parts/ImageSwiper.vue';
 
 const UserHead = 'https://mncdn.wenlvti.net/app_static/xiangyuan/images/user/avatar.png';
+const appConfig = injectAppConfiguration();
 
 const authStore = useAuthStore();
 const userInfo = computed(() => authStore.isLogged ? authStore.userInfo : null);