Skip to content

Commit

Permalink
Semi
Browse files Browse the repository at this point in the history
  • Loading branch information
sheepzh committed Aug 21, 2024
1 parent d03b70a commit b431241
Show file tree
Hide file tree
Showing 13 changed files with 232 additions and 159 deletions.
10 changes: 10 additions & 0 deletions src/app/components/Report/ReportFilter/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { StatQueryParam } from "@service/stat-service"
import { ReportFilterOption } from "../context"

export const cvtOption2Param = (filterOption: ReportFilterOption): StatQueryParam => ({
host: filterOption.host,
date: filterOption.dateRange,
mergeHost: filterOption.mergeHost,
mergeDate: filterOption.mergeDate,
inclusiveRemote: filterOption.readRemote,
})
13 changes: 11 additions & 2 deletions src/app/components/Report/ReportFilter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import { daysAgo } from "@util/time"
import { ElButton } from "element-plus"
import { DeleteFilled } from "@element-plus/icons-vue"
import { useState } from "@hooks"
import { ReportFilterOption } from "../context"
import { exportCsv, exportJson } from "../file-export"
import statService from "@service/stat-service"
import { cvtOption2Param } from "./common"

function datePickerShortcut(text: string, agoOfStart?: number, agoOfEnd?: number): ElementDatePickerShortcut {
const value = daysAgo(agoOfStart || 0, agoOfEnd || 0)
Expand All @@ -32,14 +36,19 @@ const dateShortcuts: ElementDatePickerShortcut[] = [
datePickerShortcut(t(msg => msg.calendar.range.lastDays, { n: 30 }), 30),
datePickerShortcut(t(msg => msg.calendar.range.lastDays, { n: 60 }), 60),
]
const handleDownload = async (format: FileFormat, option: ReportFilterOption) => {
const param = cvtOption2Param(option)
const rows = await statService.select(param, true)
format === 'json' && exportJson(option, rows)
format === 'csv' && exportCsv(option, rows)
}

const _default = defineComponent({
props: {
initial: Object as PropType<ReportFilterOption>
},
emits: {
change: (_filterOption: ReportFilterOption) => true,
download: (_format: FileFormat) => true,
batchDelete: (_filterOption: ReportFilterOption) => true,
},
setup(props, ctx) {
Expand Down Expand Up @@ -98,7 +107,7 @@ const _default = defineComponent({
{t(msg => msg.report.batchDelete.buttonText)}
</ElButton>
<RemoteClient onChange={setReadRemote} />
<DownloadFile onDownload={format => ctx.emit("download", format)} />
<DownloadFile onDownload={format => handleDownload(format, option.value)} />
</div>
</>
}
Expand Down
53 changes: 39 additions & 14 deletions src/app/components/Report/ReportList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,49 @@
import { defineComponent, PropType } from "vue"
import { defineComponent } from "vue"
import Item from "./Item"
import "./style"
import { ElCard } from "element-plus"
import { t } from "@app/locale"
import { useState } from "@hooks/useState"
import { DisplayComponent, useReportFilter } from "../context"
import { useScrollRequest } from "@hooks/useScrollRequest"
import { cvtOption2Param } from "../ReportFilter/common"
import statService from "@service/stat-service"

const _default = defineComponent({
props: {
data: Array as PropType<timer.stat.Row[]>,
end: Boolean,
},
setup(props, ctx) {
setup(_, ctx) {
const filterOption = useReportFilter()

const { data, loading, loadMoreAsync, end } = useScrollRequest(async (num, size) => {
const param = cvtOption2Param(filterOption.value)
const pagination = await statService.selectByPage(param, { num, size })
return pagination.list
})

const [selected, setSelected] = useState<timer.stat.Row[]>([])

ctx.expose({
getSelected: () => selected.value,
refresh: () => { },
} satisfies DisplayComponent)

return () => (
<div class="report-list">
{props.data?.map(row => (
<ElCard>
<Item value={row} />
</ElCard>
))}
return () => <>
<div class="report-list-wrapper">
<div
class="report-list"
v-infinite-scroll={loadMoreAsync}
infinite-scroll-disabled={end.value || loading.value}
>
{data.value?.map(row => (
<ElCard>
<Item value={row} />
</ElCard>
))}
</div>
<p class="scroll-info" v-loading={loading.value}>
{end.value ? t(msg => msg.report.noMore) : (loading.value ? 'Loading ...' : 'Load More')}
</p>
</div>
)
</>
},
})

Expand Down
16 changes: 13 additions & 3 deletions src/app/components/Report/ReportList/style.sass
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
.report-list
width: 100%
display: flex
flex-direction: column
gap: 10px
display: grid
gap: .6em
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr))
.el-card__body
padding: 15px
.scroll-info
height: 20px
width: 100%
text-align: center
color: var(--el-text-color-regular)
.report-item
.report-item-title
display: flex
justify-content: space-between
.report-item-content
display: flex
gap: 5px
flex-wrap: wrap
justify-content: space-between
.el-tag__content
display: flex
align-items: center
gap: 2px
.report-item-content:after
content: ""
flex: auto
112 changes: 74 additions & 38 deletions src/app/components/Report/ReportTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,99 @@
* https://opensource.org/licenses/MIT
*/
import { ElTable, ElTableColumn } from "element-plus"
import { defineComponent, type PropType } from "vue"
import { computed, defineComponent, type PropType } from "vue"
import DateColumn from "./columns/DateColumn"
import HostColumn from "./columns/HostColumn"
import FocusColumn from "./columns/FocusColumn"
import TimeColumn from "./columns/TimeColumn"
import OperationColumn from "./columns/OperationColumn"
import { useReportFilter } from "../context"
import { useState } from "@hooks"
import { DisplayComponent, ReportFilterOption, useReportFilter } from "../context"
import { useRequest, useState, useWindowVisible } from "@hooks"
import { t } from "@app/locale"
import Editable from "@app/components/common/Editable"
import ContentCard from "@app/components/common/ContentCard"
import Pagination from "@app/components/common/Pagination"
import statService, { StatQueryParam } from "@service/stat-service"
import siteService from "@service/site-service"
import { cvtOption2Param } from "../ReportFilter/common"

export type TableInstance = {
getSelected(): timer.stat.Row[]
function computeTimerQueryParam(filterOption: ReportFilterOption, sort: SortInfo): StatQueryParam {
const param = cvtOption2Param(filterOption) || {}
param.sort = sort.prop
param.sortOrder = sort.order === 'ascending' ? 'ASC' : 'DESC'
return param
}

async function handleAliasChange(key: timer.site.SiteKey, newAlias: string, data: timer.stat.Row[]) {
newAlias = newAlias?.trim?.()
if (!newAlias) {
await siteService.removeAlias(key)
} else {
await siteService.saveAlias(key, newAlias, 'USER')
}
data?.filter(item => item.host === key.host)
?.forEach(item => item.alias = newAlias)
}

const _default = defineComponent({
props: {
data: Array as PropType<timer.stat.Row[]>,
defaultSort: Object as PropType<SortInfo>,
},
emits: {
sortChange: (_newSortInfo: SortInfo) => true,
aliasChange: (_host: string, _newAlias: string) => true,
itemDelete: (_row: timer.stat.Row) => true,
},
setup(props, ctx) {
const [page, setPage] = useState<timer.common.PageQuery>({ size: 10, num: 1 })
const [sort, setSort] = useState(props.defaultSort)
const filterOption = useReportFilter()
const queryParam = computed(() => computeTimerQueryParam(filterOption.value, sort.value))
const { data, refresh } = useRequest(
() => statService.selectByPage(queryParam.value, page.value, true),
{ loadingTarget: "#report-table-content", deps: [queryParam, page] }
)
// Query data if window become visible
useWindowVisible({ onVisible: refresh })

const [selection, setSelection] = useState<timer.stat.Row[]>([])
ctx.expose({ getSelected: () => selection.value } satisfies TableInstance)
ctx.expose({
getSelected: () => selection.value,
refresh,
} satisfies DisplayComponent)

return () => (
<ElTable
data={props.data}
border
size="small"
defaultSort={props.defaultSort}
style={{ width: "100%" }}
fit
highlightCurrentRow
onSelection-change={setSelection}
onSort-change={(newSortInfo: SortInfo) => ctx.emit("sortChange", newSortInfo)}
>
<ElTableColumn type="selection" selectable={() => !filterOption.value?.mergeHost} />
{!filterOption.value?.mergeDate && <DateColumn />}
<HostColumn />
<ElTableColumn
label={t(msg => msg.siteManage.column.alias)}
minWidth={140}
align="center"
v-slots={({ row }: { row: timer.stat.Row }) => <Editable
modelValue={row.alias}
onChange={newAlias => ctx.emit("aliasChange", row.host, newAlias)}
/>}
<ContentCard id="report-table-content">
<ElTable
data={data.value?.list}
border
size="small"
defaultSort={props.defaultSort}
style={{ width: "100%" }}
fit
highlightCurrentRow
onSelection-change={setSelection}
onSort-change={(newSortInfo: SortInfo) => setSort(newSortInfo)}
>
<ElTableColumn type="selection" selectable={() => !filterOption.value?.mergeHost} />
{!filterOption.value?.mergeDate && <DateColumn />}
<HostColumn />
<ElTableColumn
label={t(msg => msg.siteManage.column.alias)}
minWidth={140}
align="center"
v-slots={({ row }: { row: timer.stat.Row }) => (
<Editable
modelValue={row.alias}
onChange={newAlias => handleAliasChange({ host: row.host, merged: filterOption.value?.mergeHost }, newAlias, data.value?.list)}
/>
)}
/>
<FocusColumn />
<TimeColumn />
<OperationColumn onDelete={refresh} />
</ElTable>
<Pagination
defaultValue={page.value}
total={data.value?.total || 0}
onChange={setPage}
/>
<FocusColumn />
<TimeColumn />
<OperationColumn onDelete={row => ctx.emit("itemDelete", row)} />
</ElTable>
</ContentCard>
)
}
})
Expand Down
17 changes: 17 additions & 0 deletions src/app/components/Report/context.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import { useProvide, useProvider } from "@hooks"
import { Ref } from "vue"

export type ReportFilterOption = {
host: string
dateRange: [Date, Date]
mergeDate: boolean
mergeHost: boolean
/**
* @since 1.1.7
*/
timeFormat: timer.app.TimeFormat
readRemote?: boolean
}

type Context = {
filter: Ref<ReportFilterOption>
}
Expand All @@ -14,3 +26,8 @@ export const initProvider = (
})

export const useReportFilter = (): Ref<ReportFilterOption> => useProvider<Context>(NAMESPACE, "filter").filter

export interface DisplayComponent {
getSelected(): timer.stat.Row[]
refresh(): Promise<void> | void
}
1 change: 1 addition & 0 deletions src/app/components/Report/file-export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
exportCsv as exportCsv_,
exportJson as exportJson_,
} from "@util/file"
import { ReportFilterOption } from "./context"

type _ExportInfo = {
host: string
Expand Down
Loading

0 comments on commit b431241

Please sign in to comment.