Skip to content

Commit

Permalink
feat: 新增支持货物出售城市数据按利润排序 (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
yjl9903 authored Mar 11, 2024
2 parents 2a26ac2 + 8fce342 commit 0843357
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 30 deletions.
114 changes: 85 additions & 29 deletions components/City.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,30 @@ const timestamp = useTimestamp({ interval: 10 * 1000 });
const mode = ref<'simple' | 'full' | 'edit'>('simple');
const store = useLatestLogs();
// 售出城市列表
const sellCities = computed(() => {
return cities.filter((c) => c.name !== currentCity.name)
})
const settingStore = useSettingStore()
// 返回对各城市利润排序后的城市列表
const sortCitesByPercent = (filteredCities: CityInfo[], sourceCityName: string, productName: string) => {
const sourceCityPrice = store.getLatestLog(sourceCityName, productName, sourceCityName)?.price || 0
// 计算各城市货物利润
let citiesProfitMap: {[key: string]: number} = {}
filteredCities.map(city => {
const latestLog = store.getLatestLog(sourceCityName, productName, city.name)
// 如果最新交易记录无效,且有最新交易记录和原产地价格,则计算利润
const profit = !Boolean(isLogValid(latestLog)) && latestLog && sourceCityPrice ? latestLog.price - sourceCityPrice : -9999
return { cityName: city.name, profit }
}).forEach(cityProfit => citiesProfitMap[cityProfit.cityName] = cityProfit.profit)
const sortedCities = filteredCities.sort((a, b) => citiesProfitMap[b.name] - citiesProfitMap[a.name])
return sortedCities
}
</script>

<template>
Expand All @@ -39,42 +63,74 @@ const store = useLatestLogs();
<CardContent>
<Table>
<TableHeader>
<TableRow class="boder-t"
><TableHead class="w-[120px]">商品</TableHead
><TableHead class="border-r">{{ currentCity.name }}</TableHead
><TableHead
v-for="city in cities.filter((c) => c.name !== currentCity.name)"
:key="city.name"
>{{ city.name }}</TableHead
><TableHead class="w-[100px]">操作</TableHead></TableRow
>
<TableRow class="boder-t">
<TableHead class="w-[120px]">商品</TableHead>
<!-- 按城市纬度排序 -->
<template v-if="settingStore.listSortMode === 'byCity'">
<TableHead class="border-r">{{ currentCity.name }}</TableHead>
<TableHead
v-for="city in sellCities"
:key="city.name"
>{{ city.name }}</TableHead>
</template>
<!-- 按利润排序 -->
<template v-else-if="settingStore.listSortMode === 'byProfit'">
<TableHead class="border-r"><div class="w-30">原产地采购价</div></TableHead>
<TableHead :colspan="sellCities.length">城市售卖报价(按利润高低从左到右降序排序)</TableHead>
</template>
<!-- 操作列 -->
<TableHead class="w-[100px]">操作</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="product in city.products.filter((p) => p.valuable)" :key="product.name">
<TableCell
><NuxtLink :to="`/product/${city.name}/${product.name}`">{{
product.name
}}</NuxtLink></TableCell
>
<TableCell class="border-r"
><Price
<TableCell>
<NuxtLink :to="`/product/${city.name}/${product.name}`">{{ product.name }}</NuxtLink>
</TableCell>
<TableCell class="border-r">
<Price
:sort-mode="settingStore.listSortMode"
:timestamp="timestamp"
:product="getProductInfo(city.name, product.name)!"
:transaction="undefined"
:log="store.getLatestLog(city.name, product.name, city.name)"
></Price
></TableCell>
<TableCell
v-for="target in cities.filter((c) => c.name !== currentCity.name)"
:key="target.name"
><Price
:timestamp="timestamp"
:product="getProductInfo(city.name, product.name)!"
:transaction="getTransactionInfo(city.name, product.name, target.name)"
:log="store.getLatestLog(city.name, product.name, target.name)"
></Price
></TableCell>
<TableCell><CreateLog :city="city" :product="product"></CreateLog></TableCell>
/>
</TableCell>
<!-- 按城市纬度排序 -->
<template v-if="settingStore.listSortMode === 'byCity'">
<TableCell
v-for="target in sellCities"
:key="target.name"
>
<Price
:sort-mode="settingStore.listSortMode"
:timestamp="timestamp"
:product="getProductInfo(city.name, product.name)!"
:transaction="getTransactionInfo(city.name, product.name, target.name)"
:log="store.getLatestLog(city.name, product.name, target.name)"
/>
</TableCell>
</template>
<!-- 按利润排序 -->
<template v-if="settingStore.listSortMode === 'byProfit'">
<TableCell
v-for="target in sortCitesByPercent(sellCities, city.name, product.name)"
:key="target.name"
class="w-40"
>
<Price
:sort-mode="settingStore.listSortMode"
:timestamp="timestamp"
:product="getProductInfo(city.name, product.name)!"
:transaction="getTransactionInfo(city.name, product.name, target.name)"
:log="store.getLatestLog(city.name, product.name, target.name)"
/>
</TableCell>
</template>
<!-- 操作单元格 -->
<TableCell>
<CreateLog :city="city" :product="product"></CreateLog>
</TableCell>
</TableRow>
</TableBody>
</Table>
Expand Down
8 changes: 7 additions & 1 deletion components/Price.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { Log } from '~/drizzle/schema';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
const props = defineProps<{
sortMode: 'byProfit' | 'byCity';
timestamp: number;
product: ProductInfo;
transaction: TransactionInfo | undefined;
Expand Down Expand Up @@ -93,7 +94,12 @@ const shortTime = computed(() => {
<TooltipProvider v-if="log && shortTime" :delayDuration="300" :skipDelayDuration="100">
<Tooltip v-model:open="openTooltip">
<TooltipTrigger as-child>
<div :class="[{ 'op-50': isOutdated }, 'space-y-1']" @touchstart="openTooltip = true">
<div :class="[{ 'op-50': isOutdated }, 'space-y-1']" @click="openTooltip = true">
<!-- 所在城市 -->
<div v-if="sortMode == 'byProfit'" class="flex gap-1 items-center text-base-600">
<span class="i-icon-park-outline-city-one text-sm"></span>
<span >{{ log.targetCity }}</span>
</div>
<div
v-if="log.type === 'sell'"
:class="['h-6 flex gap-1 items-center', { 'line-through': isOutdated }]"
Expand Down
31 changes: 31 additions & 0 deletions layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
MenubarTrigger,
MenubarButton
} from '@/components/ui/menubar';
const settingStore = useSettingStore()
</script>

<template>
Expand Down Expand Up @@ -88,6 +90,35 @@ import {
</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>列表排序</MenubarTrigger>
<MenubarContent>
<MenubarItem as-child>
<a
class="hover:bg-gray-100 cursor-pointer flex justify-between"
@click="settingStore.switchListSortModeTo('byCity')"
>
<div class="flex items-center">
<span class="i-icon-park-outline-city-one mr-1 block w-4"></span>
<span>按城市排序</span>
</div>
<span v-if="settingStore.listSortMode === 'byCity'" class="i-material-symbols-check"></span>
</a>
</MenubarItem>
<MenubarItem as-child>
<a
class="hover:bg-gray-100 cursor-pointer flex justify-between"
@click="settingStore.switchListSortModeTo('byProfit')"
>
<div class="flex items-center">
<span class="i-icon-park-outline-income-one mr-1 block w-4"></span>
<span>按利润排序</span>
</div>
<span v-if="settingStore.listSortMode === 'byProfit'" class="i-material-symbols-check"></span>
</a>
</MenubarItem>
</MenubarContent>
</MenubarMenu>
<!-- <MenubarMenu>
<MenubarTrigger>Edit</MenubarTrigger>
<MenubarContent>
Expand Down
15 changes: 15 additions & 0 deletions stores/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export type ListSortMode = 'byCity' | 'byProfit'

export const useSettingStore = defineStore('setting', () => {
const listSortMode = ref<ListSortMode>('byCity')

// 切换列表排序模式
const switchListSortModeTo = (targetMode: ListSortMode) => {
listSortMode.value = targetMode
}

return {
listSortMode,
switchListSortModeTo
}
})

0 comments on commit 0843357

Please sign in to comment.