feat mobile handmade mall grid
This commit is contained in:
@@ -1,40 +1,25 @@
|
||||
<template>
|
||||
<section v-if="!isDetail" class="m-task-mall" :style="{ backgroundImage: `url(${mobileAssets.mallBackground})` }">
|
||||
<header class="m-mall-search">
|
||||
<h1>商城</h1>
|
||||
<label><n-icon :component="SearchOutline" /><input v-model.trim="keyword" placeholder="搜索商品" /></label>
|
||||
<button type="button" @click="applySearch">搜索</button>
|
||||
</header>
|
||||
<PageHeader title="手工商城" />
|
||||
|
||||
<img class="m-mall-banner" :src="mobileAssets.mallBanner" alt="精选任务,轻松赚收益" />
|
||||
|
||||
<div class="m-mall-tabs">
|
||||
<button :class="{ active: tab === 'recommended' }" @click="tab = 'recommended'">推荐任务</button>
|
||||
<button :class="{ active: tab === 'limited' }" @click="tab = 'limited'">限时任务</button>
|
||||
<n-icon :component="ChevronForwardOutline" />
|
||||
</div>
|
||||
|
||||
<AsyncState
|
||||
:loading="loading"
|
||||
:error="error"
|
||||
:empty="!visibleProducts.length"
|
||||
:empty-text="tab === 'limited' ? '暂无限时任务' : '暂无推荐任务'"
|
||||
:empty="!products.length"
|
||||
empty-text="暂无手工商品"
|
||||
@retry="loadList"
|
||||
>
|
||||
<div class="m-mall-list">
|
||||
<article v-for="item in visibleProducts" :key="item.id" class="m-mall-task">
|
||||
<button class="m-mall-cover" @click="openProduct(item.id)">
|
||||
<button v-for="item in products" :key="item.id" class="m-mall-task" type="button" @click="openSupport">
|
||||
<span class="m-mall-cover">
|
||||
<img v-if="safeImage(item.cover_url)" :src="safeImage(item.cover_url)" :alt="item.name" />
|
||||
<n-icon v-else :component="ImageOutline" />
|
||||
<span v-if="item.is_limited">限时展示</span>
|
||||
</button>
|
||||
<div>
|
||||
<h2>{{ item.name }}</h2>
|
||||
<strong>{{ money(item.price_amount, item.currency) }}<small>/件</small></strong>
|
||||
<p>已领取{{ item.claimed_count || 0 }}</p>
|
||||
</div>
|
||||
<button class="m-mall-claim" @click="openProduct(item.id)">{{ tab === 'limited' ? '抢单' : '领取' }}</button>
|
||||
</article>
|
||||
</span>
|
||||
<strong>{{ item.name }}</strong>
|
||||
<small>已领取:{{ item.claimed_count || 0 }}</small>
|
||||
</button>
|
||||
</div>
|
||||
</AsyncState>
|
||||
</section>
|
||||
@@ -76,7 +61,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { ChevronForwardOutline, ImageOutline, SearchOutline } from '@vicons/ionicons5';
|
||||
import { ImageOutline } from '@vicons/ionicons5';
|
||||
import PageHeader from '../components/PageHeader.vue';
|
||||
import AsyncState from '../components/AsyncState.vue';
|
||||
import { errorText, money, request, safeImage } from '../api';
|
||||
@@ -89,29 +74,9 @@
|
||||
const error = ref('');
|
||||
const products = ref<any[]>([]);
|
||||
const product = ref<any>();
|
||||
const keyword = ref('');
|
||||
const submittedKeyword = ref('');
|
||||
const tab = ref<'recommended' | 'limited'>('recommended');
|
||||
let listController: AbortController | undefined;
|
||||
|
||||
const isLimited = (item: any) => item.is_limited === true;
|
||||
const visibleProducts = computed(() => {
|
||||
let items = products.value;
|
||||
if (tab.value === 'limited') {
|
||||
items = items.filter(isLimited);
|
||||
} else {
|
||||
const recommended = items.filter((item) => item.is_recommended && !isLimited(item));
|
||||
items = recommended.length ? recommended : items.filter((item) => !isLimited(item));
|
||||
}
|
||||
const query = submittedKeyword.value.toLocaleLowerCase('zh-CN');
|
||||
return query ? items.filter((item) => String(item.name || '').toLocaleLowerCase('zh-CN').includes(query)) : items;
|
||||
});
|
||||
|
||||
function applySearch() {
|
||||
submittedKeyword.value = keyword.value;
|
||||
}
|
||||
function openProduct(id: number) {
|
||||
router.push(`/app/mall/${id}`);
|
||||
function openSupport() {
|
||||
router.push({ name: 'MobileSupport' });
|
||||
}
|
||||
async function loadList() {
|
||||
listController?.abort();
|
||||
|
||||
Reference in New Issue
Block a user