mirror of
https://git.hmsn.ink/kospo/svcm/oa.git
synced 2026-03-20 04:22:25 +09:00
134 lines
2.9 KiB
Vue
134 lines
2.9 KiB
Vue
<script lang="ts">
|
|
import type { SlotsType } from 'vue'
|
|
import type {
|
|
RouteLocationOptions,
|
|
LocationQueryValue,
|
|
} from 'vue-router/auto'
|
|
import { RouterLink } from 'vue-router'
|
|
|
|
export default defineComponent({
|
|
props: {
|
|
id: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
label: {
|
|
type: String,
|
|
default: undefined,
|
|
},
|
|
modelValue: {
|
|
type: String,
|
|
default: undefined,
|
|
},
|
|
noRouter: {
|
|
type: Boolean,
|
|
default: undefined,
|
|
},
|
|
routerQueryKey: {
|
|
type: String,
|
|
default: 'sort',
|
|
},
|
|
},
|
|
slots: Object as SlotsType<{
|
|
default: {
|
|
isDesc: boolean
|
|
isAsc: boolean
|
|
nextSort?: string
|
|
value: string | LocationQueryValue[]
|
|
}
|
|
}>,
|
|
emits: ['update:modelValue'],
|
|
setup(props, context) {
|
|
const route = useRoute()
|
|
const rawSort = computed(
|
|
() => props.modelValue ?? route.query[props.routerQueryKey] ?? '',
|
|
)
|
|
|
|
const isAsc = computed(() => rawSort.value === `${props.id}:asc`)
|
|
const isDesc = computed(() => rawSort.value === `${props.id}:desc`)
|
|
|
|
const nextSort = computed(() => {
|
|
return isAsc.value
|
|
? `${props.id}:desc`
|
|
: isDesc.value
|
|
? undefined
|
|
: `${props.id}:asc`
|
|
})
|
|
|
|
const sortedLink = computed(() => {
|
|
if (props.noRouter) {
|
|
return {}
|
|
}
|
|
|
|
const query: any = {
|
|
...route.query,
|
|
}
|
|
|
|
if (props.routerQueryKey) {
|
|
query[props.routerQueryKey] = nextSort.value
|
|
}
|
|
|
|
return {
|
|
name: route.name,
|
|
params: route.params,
|
|
query: query,
|
|
} as RouteLocationOptions
|
|
})
|
|
|
|
const handleLinkClick = (e: MouseEvent) => {
|
|
context.emit('update:modelValue', nextSort.value)
|
|
|
|
if (props.noRouter) {
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
|
|
return false
|
|
}
|
|
}
|
|
|
|
return () => {
|
|
const slotContent = context.slots?.default?.({
|
|
isDesc: isDesc.value,
|
|
isAsc: isAsc.value,
|
|
nextSort: nextSort.value,
|
|
value: rawSort.value,
|
|
})
|
|
|
|
const link = h(
|
|
RouterLink,
|
|
{
|
|
to: sortedLink.value,
|
|
onClick: handleLinkClick,
|
|
onKeydown(e: KeyboardEvent) {
|
|
if (e.code === 'Space') {
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
|
|
if (e.target instanceof HTMLAnchorElement) {
|
|
e.target.dispatchEvent(new MouseEvent('click'))
|
|
}
|
|
}
|
|
},
|
|
},
|
|
{
|
|
default() {
|
|
const icon = h('iconify-icon', {
|
|
class: 'ml-3 iconify',
|
|
icon: isAsc.value
|
|
? 'fa6-solid:sort-up'
|
|
: isDesc.value
|
|
? 'fa6-solid:sort-down'
|
|
: 'fa6-solid:sort',
|
|
})
|
|
|
|
return [slotContent ?? props.label, icon]
|
|
},
|
|
},
|
|
)
|
|
|
|
return h('span', {}, link)
|
|
}
|
|
},
|
|
})
|
|
</script>
|