refactor(page): refactor system -> template

This commit is contained in:
qianmoQ 2024-11-07 10:44:43 +08:00
parent d0f8cc207c
commit 39d9c211b4
3 changed files with 164 additions and 189 deletions

View File

@ -1,74 +1,72 @@
<template> <template>
<div class="w-full"> <ShadcnCard>
<DataCapCard> <template #title>
<template #title>{{ $t('template.common.list') }}</template> <div class="ml-2 font-normal text-sm">{{ $t('template.common.list') }}</div>
<template #extra> </template>
<Button size="icon" class="ml-auto gap-1 h-6 w-6" @click="handlerInfo(true, null)">
<Plus :size="20"/> <template #extra>
</Button> <ShadcnButton size="small" circle @click="handlerInfo(true, null)">
</template> <template #icon>
<TableCommon :loading="loading" :columns="headers" :data="data" :pagination="pagination" @changePage="handlerChangePage"> <ShadcnIcon icon="Plus"/>
<template #plugin="{row}">
<div class="flex items-center p-4 sm:justify-between">
<div class="flex -space-x-2 overflow-hidden">
<Avatar v-for="item in row?.plugin.split(',')" size="sm" class="border-2 border-background w-8 h-8">
<AvatarImage :src="'/static/images/plugin/' + item + '.png'"/>
<AvatarFallback>{{ item }}</AvatarFallback>
</Avatar>
</div>
</div>
</template> </template>
</ShadcnButton>
</template>
<div class="relative">
<ShadcnSpin v-if="loading" fixed/>
<ShadcnTable size="small" :columns="headers" :data="data">
<template #plugin="{ row }">
<ShadcnAvatar v-for="item in row?.plugin.split(',')"
size="small"
:src="'/static/images/plugin/' + item + '.png'"
:alt="item"/>
</template>
<template #system="{ row }"> <template #system="{ row }">
<Switch disabled :default-checked="row?.system"/> <ShadcnSwitch v-model="row.system" size="small" :disabled="row.system"/>
</template> </template>
<template #action="{row}">
<TooltipProvider :delay-duration="0"> <template #action="{ row }">
<Tooltip> <ShadcnSpace>
<TooltipTrigger as-child> <ShadcnTooltip :content="$t('common.editData')">
<Button variant="outline" size="icon" class="rounded-full w-8 h-8" @click="handlerInfo(true, row)"> <ShadcnButton size="small" circle @click="handlerInfo(true, row)">
<Pencil :size="15"></Pencil> <ShadcnIcon icon="Pencil" size="15"/>
</Button> </ShadcnButton>
</TooltipTrigger> </ShadcnTooltip>
<TooltipContent> </ShadcnSpace>
<p>{{ $t('common.editData') }}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</template> </template>
</TableCommon> </ShadcnTable>
</DataCapCard>
</div> <ShadcnPagination v-model="pageIndex"
class="py-2"
show-total
show-sizer
:page-size="pageSize"
:total="dataCount"
:sizerOptions="[10, 20, 50]"
@on-change="onPageChange"
@on-prev="onPrevChange"
@on-next="onNextChange"
@on-change-size="onSizeChange"/>
</div>
</ShadcnCard>
<TemplateInfo v-if="dataInfoVisible" :is-visible="dataInfoVisible" :info="dataInfo" @close="handlerInfo(false, null)"/> <TemplateInfo v-if="dataInfoVisible" :is-visible="dataInfoVisible" :info="dataInfo" @close="handlerInfo(false, null)"/>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import { DataCapCard } from '@/views/ui/card'
import TableCommon from '@/views/components/table/TableCommon.vue'
import { Button } from '@/components/ui/button'
import { FilterModel } from '@/model/filter' import { FilterModel } from '@/model/filter'
import { createHeaders } from '@/views/pages/system/template/TemplateUtils' import { createHeaders } from '@/views/pages/system/template/TemplateUtils'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { PaginationModel, PaginationRequest } from '@/model/pagination'
import TemplateService from '@/services/template' import TemplateService from '@/services/template'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
import { TemplateModel } from '@/model/template' import { TemplateModel } from '@/model/template'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Switch } from '@/components/ui/switch'
import TemplateInfo from '@/views/pages/system/template/TemplateInfo.vue' import TemplateInfo from '@/views/pages/system/template/TemplateInfo.vue'
export default defineComponent({ export default defineComponent({
name: 'TemplateHome', name: 'TemplateHome',
components: { components: { TemplateInfo },
DataCapCard,
TemplateInfo,
Switch,
Button,
Pencil, Plus, Import, Cog,
TableCommon,
Tooltip, TooltipContent, TooltipProvider, TooltipTrigger,
Avatar, AvatarFallback, AvatarImage
},
setup() setup()
{ {
const filter: FilterModel = new FilterModel() const filter: FilterModel = new FilterModel()
@ -85,7 +83,9 @@ export default defineComponent({
loading: false, loading: false,
dataInfoVisible: false, dataInfoVisible: false,
data: [] as TemplateModel[], data: [] as TemplateModel[],
pagination: {} as PaginationModel, pageIndex: 1,
pageSize: 10,
dataCount: 0,
dataInfo: null as TemplateModel | null dataInfo: null as TemplateModel | null
} }
}, },
@ -101,17 +101,36 @@ export default defineComponent({
.then((response) => { .then((response) => {
if (response.status) { if (response.status) {
this.data = response.data.content this.data = response.data.content
this.pagination = PaginationRequest.of(response.data) this.dataCount = response.data.total
this.pageSize = response.data.size
this.pageIndex = response.data.page
} }
}) })
.finally(() => this.loading = false) .finally(() => this.loading = false)
}, },
handlerChangePage(value: PaginationModel) fetchData(value: number)
{ {
this.filter.page = value.currentPage this.filter.page = value
this.filter.size = value.pageSize this.filter.size = this.pageSize
this.handlerInitialize() this.handlerInitialize()
}, },
onPageChange(value: number)
{
this.fetchData(value)
},
onPrevChange(value: number)
{
this.fetchData(value)
},
onNextChange(value: number)
{
this.fetchData(value)
},
onSizeChange(value: number)
{
this.pageSize = value
this.fetchData(this.pageIndex)
},
handlerInfo(opened: boolean, value: null | TemplateModel) handlerInfo(opened: boolean, value: null | TemplateModel)
{ {
this.dataInfoVisible = opened this.dataInfoVisible = opened

View File

@ -1,101 +1,64 @@
<template> <template>
<Sheet :open="visible" class="w-full" @update:open="handlerCancel"> <ShadcnDrawer v-model="visible" :title="title" width="40%">
<SheetContent class="min-w-[25%]"> <ShadcnSpin v-if="loading" fixed/>
<SheetHeader class="border-b pb-3">
<SheetTitle class="-mt-3">{{ title }}</SheetTitle> <ShadcnForm v-model="formState" v-if="formState" @on-submit="onSubmit">
</SheetHeader> <ShadcnFormItem name="name"
<CircularLoading v-if="loading" :show="loading"/> :label="$t('common.name')"
<div v-else class="grid gap-4 py-4"> :rules="[
<FormField v-slot="{ componentField }" name="name"> { required: true, message: $t('common.name') }
<FormItem> ]">
<FormLabel>{{ $t('common.name') }}</FormLabel> <ShadcnInput v-model="formState.name" name="name" :disabled="formState.system"/>
<FormControl> </ShadcnFormItem>
<Input v-model="formState.name" :default-value="formState.name" :disabled="formState.system" v-bind="componentField"/>
</FormControl> <ShadcnFormItem name="plugin"
</FormItem> :label="$t('common.plugin')"
</FormField> :rules="[
<FormField v-slot="{ componentField }" name="plugin"> { required: true, message: $t('function.tip.selectPluginHolder') },
<FormItem> ]">
<FormLabel>{{ $t('common.plugin') }}</FormLabel> <ShadcnCheckboxGroup v-model="formState.plugin" name="plugin">
<FormControl> <ShadcnCheckbox v-for="item in plugins" :value="item.name">{{ item.name }} ({{ item.type }})</ShadcnCheckbox>
<div> </ShadcnCheckboxGroup>
<DropdownMenu> </ShadcnFormItem>
<DropdownMenuTrigger as-child>
<Button variant="outline" class="col-span-3"> <ShadcnFormItem name="description" :label="$t('common.description')">
{{ $t('function.tip.selectPluginHolder') }} <ShadcnInput v-model="formState.description" name="description" type="textarea"/>
<span v-if="formState.plugin" class="ml-1">[ {{ formState.plugin.split(',').length }} ]</span> </ShadcnFormItem>
</Button>
</DropdownMenuTrigger> <ShadcnFormItem name="content"
<DropdownMenuContent class="max-h-48 overflow-y-auto"> :label="$t('common.content')"
<DropdownMenuCheckboxItem class="cursor-pointer" v-for="plugin in plugins" v-model:checked="plugin.checked" @update:checked="setChecked" :rules="[{ required: true, message: $t('common.content') }]">
v-bind="componentField"> <AceEditor :value="formState.content" name="content" @update:value="setContent"/>
{{ (plugin as any).name }} </ShadcnFormItem>
</DropdownMenuCheckboxItem>
</DropdownMenuContent> <div class="flex justify-end">
</DropdownMenu> <ShadcnSpace>
</div> <ShadcnButton type="error"
</FormControl> :loading="saving"
</FormItem> :disabled="saving"
</FormField> @click="onCancel()">
<FormField v-slot="{ componentField }" name="description"> {{ $t('common.cancel') }}
<FormItem> </ShadcnButton>
<FormLabel>{{ $t('common.description') }}</FormLabel> <ShadcnButton submit :loading="saving" :disabled="saving">
<FormControl>
<Textarea v-model="formState.description" :default-value="formState.description" v-bind="componentField"/>
</FormControl>
</FormItem>
</FormField>
<FormField v-slot="{ componentField }" name="content">
<FormItem>
<FormLabel>{{ $t('common.content') }}</FormLabel>
<FormControl>
<AceEditor :value="formState.content" v-bind="componentField" @update:value="setContent"/>
</FormControl>
</FormItem>
</FormField>
</div>
<SheetFooter class="absolute bottom-0 left-0 right-0 mb-3 mr-3 pt-3 border-t">
<SheetClose as-child>
<Button :disabled="saving" variant="destructive" @click="handlerCancel()">{{ $t('common.cancel') }}</Button>
<Button :disabled="saving" @click="handlerSave()">
<Loader2 v-if="saving" class="w-full justify-center animate-spin"/>
{{ $t('common.save') }} {{ $t('common.save') }}
</Button> </ShadcnButton>
</SheetClose> </ShadcnSpace>
</SheetFooter> </div>
</SheetContent> </ShadcnForm>
</Sheet> </ShadcnDrawer>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import { TemplateModel, TemplateRequest } from '@/model/template' import { TemplateModel, TemplateRequest } from '@/model/template'
import { Textarea } from '@/components/ui/textarea'
import { Sheet, SheetClose, SheetContent, SheetFooter, SheetHeader, SheetTitle } from '@/components/ui/sheet'
import { ToastUtils } from '@/utils/toast'
import { Label } from '@/components/ui/label'
import { Input } from '@/components/ui/input'
import SourceService from '@/services/source' import SourceService from '@/services/source'
import TemplateService from '@/services/template' import TemplateService from '@/services/template'
import { Button } from '@/components/ui/button'
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
import { cloneDeep } from 'lodash' import { cloneDeep } from 'lodash'
import CircularLoading from '@/views/components/loading/CircularLoading.vue'
import AceEditor from '@/views/components/editor/AceEditor.vue' import AceEditor from '@/views/components/editor/AceEditor.vue'
export default defineComponent({ export default defineComponent({
name: 'TemplateInfo', name: 'TemplateInfo',
components: { components: { AceEditor },
AceEditor,
CircularLoading,
Button,
Input,
Label,
SheetClose, SheetFooter, SheetTitle, SheetHeader, Sheet, SheetContent,
Textarea,
DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger,
},
computed: { computed: {
visible: { visible: {
get(): boolean get(): boolean
@ -133,10 +96,10 @@ export default defineComponent({
methods: { methods: {
handlerInitialize() handlerInitialize()
{ {
this.title = `${this.$t('template.common.create')}` this.title = `${ this.$t('template.common.create') }`
if (this.info) { if (this.info) {
this.formState = cloneDeep(this.info) this.formState = cloneDeep(this.info)
this.title = `${this.$t('template.common.modify').replace('$NAME', this.info.name as string)}` this.title = `${ this.$t('template.common.modify').replace('$NAME', this.info.name as string) }`
} }
else { else {
this.formState = TemplateRequest.of() this.formState = TemplateRequest.of()
@ -144,48 +107,41 @@ export default defineComponent({
this.loading = true this.loading = true
SourceService.getPlugins() SourceService.getPlugins()
.then(response => { .then(response => {
if (response.status) { if (response.status) {
this.plugins = Object.values(response.data).reduce((acc, curr) => (acc as any).concat(curr), []) as any[] this.plugins = Object.values(response.data).reduce((acc, curr) => (acc as any).concat(curr), []) as any[]
this.formState.plugin?.split(',').forEach(formPlugin => { }
const foundPlugin = this.plugins.find(plugin => plugin.name === formPlugin) })
if (foundPlugin) { .finally(() => this.loading = false)
foundPlugin.checked = true
}
})
this.setChecked()
}
})
.finally(() => this.loading = false)
},
handlerSave()
{
this.saving = true
TemplateService.saveOrUpdate(this.formState)
.then((response) => {
if (response.status) {
ToastUtils.success('Create successful')
this.handlerCancel()
}
else {
ToastUtils.error(response.message)
}
})
.finally(() => this.saving = false)
},
handlerCancel()
{
this.$emit('close', false)
},
setChecked()
{
this.formState.plugin = this.plugins.filter(it => it.checked)
.map(it => it.name)
.join(',')
}, },
setContent(value: string) setContent(value: string)
{ {
this.formState.content = value this.formState.content = value
},
onSubmit()
{
this.saving = true
TemplateService.saveOrUpdate(this.formState)
.then((response) => {
if (response.status) {
this.$Message.success({
content: 'Create successful',
showIcon: true
})
this.onCancel()
}
else {
this.$Message.error({
content: response.message,
showIcon: true
})
}
})
.finally(() => this.saving = false)
},
onCancel()
{
this.$emit('close', false)
} }
} }
}) })

View File

@ -1,13 +1,13 @@
const createHeaders = (i18n: any) => { const createHeaders = (i18n: any) => {
return [ return [
{key: 'id', hidden: true, header: i18n.t('common.id')}, { key: 'id', label: i18n.t('common.id') },
{key: 'name', hidden: true, header: i18n.t('common.name')}, { key: 'name', label: i18n.t('common.name') },
{key: 'description', hidden: true, header: i18n.t('common.description')}, { key: 'description', label: i18n.t('common.description') },
{key: 'plugin', hidden: true, header: i18n.t('common.plugin'), slot: 'plugin', class: 'text-center'}, { key: 'plugin', label: i18n.t('common.plugin'), slot: 'plugin' },
{key: 'system', hidden: true, header: i18n.t('common.system'), slot: 'system', width: 120, class: 'text-center'}, { key: 'system', label: i18n.t('common.system'), slot: 'system' },
{key: 'createTime', hidden: true, header: i18n.t('common.createTime'), width: 160, class: 'text-center'}, { key: 'createTime', label: i18n.t('common.createTime') },
{key: 'updateTime', hidden: true, header: i18n.t('common.updateTime'), width: 160, class: 'text-center'}, { key: 'updateTime', label: i18n.t('common.updateTime') },
{key: 'action', hidden: true, header: i18n.t('common.action'), slot: 'action', class: 'text-right'} { key: 'action', label: i18n.t('common.action'), slot: 'action' }
] ]
} }