zhengyiming
2025-02-11 d853816c959089a545f57a2980ca3f42fdd20fa1
feat: 首页
7个文件已修改
3个文件已添加
324 ■■■■■ 已修改文件
apps/cMiniApp/src/assets/tabbar/icon-mine-active.png 补丁 | 查看 | 原始文档 | blame | 历史
apps/cMiniApp/src/assets/tabbar/icon-task-active.png 补丁 | 查看 | 原始文档 | blame | 历史
apps/cMiniApp/src/components/Layout/PageLayoutWithBg.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/cMiniApp/src/components/Menu/MenuItem.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/cMiniApp/src/components/Searchbar/BlSearchbar.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/cMiniApp/src/pages/home/constants/index.ts 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/cMiniApp/src/pages/home/index.vue 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/Card/TaskCard.vue 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/Card/TaskPrice.vue 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
packages/components/src/index.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
apps/cMiniApp/src/assets/tabbar/icon-mine-active.png

apps/cMiniApp/src/assets/tabbar/icon-task-active.png

apps/cMiniApp/src/components/Layout/PageLayoutWithBg.vue
@@ -10,8 +10,8 @@
    <template #bg>
      <img :src="OssAssets.common.CommonPageBg" class="common-page-bg" />
    </template>
    <template #default>
      <slot />
    <template #default="{ scrollViewHeight }">
      <slot :scrollViewHeight="scrollViewHeight" />
    </template>
  </PageLayout>
</template>
apps/cMiniApp/src/components/Menu/MenuItem.vue
@@ -53,10 +53,14 @@
  </view>
</template>
<script lang="ts">
import { MenuItemOption } from '@nutui/nutui-taro/dist/types/__VUE/menuitem/type';
import { Check } from '@nutui/icons-vue-taro';
import { isArray } from 'lodash';
type MenuItemOption = {
  text: string;
  value: number | string;
};
export default defineComponent({
  name: 'bl-menu-item',
  props: {
apps/cMiniApp/src/components/Searchbar/BlSearchbar.vue
@@ -25,5 +25,10 @@
.bole-search-bar {
  padding: 0;
  background-color: transparent;
  .nut-searchbar__search-input {
    box-shadow: none;
    border: 1px solid boleGetCssVar('color', 'primary');
  }
}
</style>
apps/cMiniApp/src/pages/home/constants/index.ts
New file
@@ -0,0 +1,4 @@
export enum HomeOrderType {
  Recommend = 'Recommend',
  LastShelfTime = 'LastShelfTime',
}
apps/cMiniApp/src/pages/home/index.vue
@@ -1,31 +1,91 @@
<template>
  <PageLayoutWithBg class="index-page-wrapper" :title="'首页'" :need-auth="false">
  <PageLayoutWithBg class="index-page-wrapper" :title="''" :need-auth="false">
    <template #left>
      <div class="menu-btn-wrapper menu-logo">
        <img :src="IconLogo" class="logo" />
      </div>
    </template>
    <div class="home-header">
    <div class="home-searchbar-wrapper">
      <BlSearchbar v-model.trim="searchValue"></BlSearchbar>
        <div class="searchbar-container">
          <BlSearchbar v-model.trim="searchValue" placeholder="搜索任务"></BlSearchbar>
    </div>
        <div class="city-btn" @click="goCitySelect">
          <Location2 :size="16" />
          <div class="city-btn-text">{{ locationCity }}</div>
        </div>
      </div>
      <div class="home-banner-wrapper">
        <nut-swiper :auto-play="3000">
          <nut-swiper-item v-for="(item, index) in list" :key="index">
            <img :src="item" class="banner-img" draggable="false" />
          </nut-swiper-item>
        </nut-swiper>
      </div>
    </div>
    <ProTabs
      v-model="queryState.orderType"
      name="home-tab"
      :showPaneContent="false"
      class="home-tabs"
      isTransparent
      title-gutter="12"
      title-scroll
    >
      <ProTabPane :title="`推荐`" :pane-key="HomeOrderType.Recommend"></ProTabPane>
      <ProTabPane :title="`最新`" :pane-key="HomeOrderType.LastShelfTime"></ProTabPane>
      <template #right>
        <Menu>
          <MenuItem
            v-model="queryState.orderByProperty"
            title="筛选"
            ref="selectItem"
            :options="[
              { text: '排序', value: 'userId' },
              { text: '按关注时间', value: 'creationTime' },
            ]"
          />
        </Menu>
      </template>
    </ProTabs>
    <InfiniteLoading
      scrollViewClassName="common-infinite-scroll-list home-list"
      v-bind="infiniteLoadingProps"
      :key="queryState.orderType"
    >
      <template #renderItem="{ item }">
        <TaskCard />
      </template>
    </InfiniteLoading>
  </PageLayoutWithBg>
</template>
<script setup lang="ts">
import { useUser } from '@/hooks';
import { useUserStore } from '@/stores/modules/user';
import { RectDown } from '@nutui/icons-vue-taro';
import { RectDown, Location2 } from '@nutui/icons-vue-taro';
import Taro from '@tarojs/taro';
import { LocationUtils, trim } from '@12333/utils';
import _ from 'lodash';
import IconLogo from '@/assets/home/icon-logo.png';
import { useInfiniteLoading } from '@12333/hooks';
import { OrderInputType } from '@12333/constants';
import * as orderServices from '@12333/services/api/Order';
import { TaskCard, ProTabs, ProTabPane } from '@12333/components';
import { HomeOrderType } from './constants';
const { locationCity } = useUser();
Taro.usePageScroll(() => {
  console.log('11', 11);
});
const searchValue = ref('');
const queryState = reactive({
  searchValueTrim: '',
  orderType: HomeOrderType.Recommend,
  orderByProperty: 'userId',
});
const handleSearch = _.debounce(function () {
@@ -39,13 +99,36 @@
    url: RouterPath.citySelect,
  });
}
// onMounted(async () => {
//   if (!isSetMatchMakingIdentity.value) {
//     Taro.navigateTo({
//       url: RouterPath.toggleMatchMakingIdentity,
//     });
//   }
// });
const list = ref([
  'https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg',
  'https://storage.360buyimg.com/jdc-article/NutUItaro2.jpg',
  'https://storage.360buyimg.com/jdc-article/welcomenutui.jpg',
  'https://storage.360buyimg.com/jdc-article/fristfabu.jpg',
]);
const { infiniteLoadingProps } = useInfiniteLoading(
  ({ pageParam }) => {
    let params: API.FrontOrderListInput = {
      pageModel: {
        rows: 20,
        page: pageParam,
        orderInput: [
          queryState.orderType === HomeOrderType.Recommend
            ? { property: 'isRecommend', order: OrderInputType.Desc }
            : { property: 'lastShelfTime', order: OrderInputType.Desc },
        ],
      },
    };
    return orderServices.getFrontOrderList(params, {
      showLoading: false,
    });
  },
  {
    queryKey: ['orderServices/getFrontOrderList', queryState],
  }
);
</script>
<style lang="scss">
@@ -61,19 +144,44 @@
    }
  }
  .home-searchbar-wrapper {
    padding: 32px 0;
    display: flex;
    .searchbar-container {
      flex: 1;
      min-width: 0;
    }
  .city-btn {
    display: flex;
    align-items: center;
      padding-left: 36px;
      color: boleGetCssVar('text-color', 'primary');
    .city-btn-text {
      max-width: 200px;
      @include ellipsis;
      margin-right: 12px;
        margin-left: 12px;
        font-size: 30px;
      }
    }
  }
  .home-searchbar-wrapper {
    padding: 32px 0;
  .home-banner-wrapper {
    .banner-img {
      width: 100%;
      height: 260px;
      object-fit: cover;
  }
}
  .home-header {
    padding: 0 boleGetCssVar('size', 'body-padding-h');
  }
}
.home-list {
  @include infiniteLoadingInTabBarPage;
}
</style>
packages/components/src/Card/TaskCard.vue
New file
@@ -0,0 +1,131 @@
<template>
  <div class="task-card-wrapper">
    <div class="task-card-title-wrapper">
      <div class="task-card-title">客房服务员</div>
      <TaskPrice />
    </div>
    <div class="task-card-welfare-list">
      <div class="task-card-welfare-list-item">日结</div>
      <div class="task-card-welfare-list-item">男女不限</div>
      <div class="task-card-welfare-list-item">包三餐</div>
    </div>
    <div class="task-card-time">上班时间:07:00-15:30</div>
    <div class="task-card-footer">
      <div class="task-card-left">
        <div class="task-card-footer-tag">H</div>
        <div class="task-card-footer-address">宁波雷迪森酒店</div>
      </div>
      <div class="task-card-actions">
        <slot name="actions">
          <nut-button type="primary">报名</nut-button>
        </slot>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import TaskPrice from './TaskPrice.vue';
defineOptions({
  name: 'TaskCard',
});
type Props = {
  title?: string;
};
const props = withDefaults(defineProps<Props>(), {});
</script>
<style lang="scss">
@import '@/styles/common.scss';
.task-card-wrapper {
  padding: 24px 32px;
  margin-bottom: 24px;
  background-color: #fff;
  border-radius: 12px;
  &:last-child {
    margin-bottom: 0;
  }
  .task-card-title-wrapper {
    display: flex;
    align-items: center;
    margin-bottom: 14px;
    .task-card-title {
      flex: 1;
      min-width: 0;
      @include ellipsis;
      font-size: 30px;
      color: boleGetCssVar('text-color', 'primary');
      line-height: 42px;
    }
  }
  .task-card-welfare-list {
    display: flex;
    flex-wrap: wrap;
    row-gap: 6px;
    column-gap: 18px;
    margin-bottom: 8px;
    .task-card-welfare-list-item {
      font-size: 24px;
      color: #ff7d00;
      line-height: 36px;
    }
  }
  .task-card-time {
    font-size: 24px;
    color: boleGetCssVar('text-color', 'secondary');
    line-height: 36px;
    margin-bottom: 6px;
  }
  .task-card-footer {
    display: flex;
    align-items: center;
    .task-card-left {
      flex: 1;
      min-width: 0;
      display: flex;
      align-items: center;
      .task-card-footer-tag {
        width: 32px;
        height: 32px;
        background: #2a9e1b;
        margin-right: 8px;
        border-radius: 8px;
        text-align: center;
        line-height: 32px;
        color: #fff;
        font-size: 22px;
      }
      .task-card-footer-address {
        font-size: 22px;
        color: boleGetCssVar('text-color', 'secondary');
        line-height: 36px;
        flex: 1;
        min-width: 0;
        @include ellipsis;
      }
    }
    .task-card-actions {
      --nut-button-default-font-size: 24px;
      .nut-button {
        height: 26px;
      }
    }
  }
}
</style>
packages/components/src/Card/TaskPrice.vue
New file
@@ -0,0 +1,39 @@
<template>
  <div class="task-price">
    <div class="task-price-decimal">55</div>
    <div class="task-price-unit">元/小时</div>
  </div>
</template>
<script setup lang="ts">
defineOptions({
  name: 'TaskPrice',
});
type Props = {
  value?: number;
};
const props = withDefaults(defineProps<Props>(), {});
</script>
<style lang="scss">
@import '@/styles/common.scss';
.task-price {
  display: flex;
  align-items: flex-end;
  color: boleGetCssVar('color', 'primary');
  .task-price-decimal {
    font-size: 32px;
    line-height: 40px;
    margin-right: 8px;
  }
  .task-price-unit {
    font-size: 20px;
    line-height: 32px;
  }
}
</style>
packages/components/src/index.ts
@@ -17,3 +17,4 @@
export { default as AutoWidthImage } from './Image/AutoWidthImage.vue';
export { default as AreaTreeSelect } from './AreaTreeSelect/AreaTreeSelect.vue';
export { default as Elevator } from './Elevator/Elevator.vue';
export { default as TaskCard } from './Card/TaskCard.vue';