主题
Tab 表单
后端
这里使用的是内容管理的文章管理用做案例
php
namespace Modules\Cms\Dynamics;
use CatchForm\Builder;
use CatchForm\Components\Rules\Control;
use CatchForm\Form;
use CatchForm\Table\Table;
use Modules\Cms\Enums\CategoryType;
use Modules\Cms\Enums\Visible;
use Modules\Cms\Models\Category as CategoryModel;
class Resource extends Builder
{
protected function form(): mixed
{
// TODO: Implement form() method.
return Form::make(function (Form $form){
$form->text('name', '名称')->required();
$form->radio('type', '类型')->options([
['value' => 1, 'label' => '轮播图'],
['value' => 2, 'label' => '友情链接'],
['value' => 3, 'label' => '广告'],
])->required()->defaultValue(1)
->asButton()
->whenEqual(2, function (Control $control){
$control->required('url');
})
->whenNotEqual(2, function (Control $control){
$control->hide('content');
})
->whenNotEqual(2, function (Control $control){
$control->required('content');
});
$form->upload('content', '上传图片');
$form->url('url', '链接');
$form->textarea('description', '描述');
$form->radio('is_visible', '可见性')->options([
['value' => 1, 'label' => '可见'],
['value' => 2, 'label' => '隐藏'],
])->required()->asButton()->defaultValue(1);
$form->radio('is_visible', '打开方式')->options([
['value' => 1, 'label' => '本窗口'],
['value' => 2, 'label' => '新窗口'],
])->required()->asButton()->defaultValue(1);
});
}
protected function table(): mixed
{
// TODO: Implement table() method.
return Table::make('/cms/resource')->columns(function (Table $table){
$table->selection();
$table->id();
$table->column('name', '名称');
$table->column('content', '图片')->image();
$table->column('url', '链接')->link(true, '链接');
$table->column('type', '类型')->tags(['danger', 'info', 'success'])
// filter 支持注入动态方法,当然也可以通过后端转换
->filter(<<<FUNC
(value) => {
return value === 1 ? '轮播图' : value === 2 ? '友情链接' : '广告'
}
FUNC
);
$table->operate();
})->search(function (Table $table){
$table->text('名称', 'name');
});
}
}
前端
列表页面
vue
<template>
<div v-loading="loading" class="min-h-96">
<catch-table v-bind="table" v-if="!loading" ref="tableRef">
<template #operation>
<router-link to="/cms/articles/create">
<Add text="创建文章" />
</router-link>
<el-button-group class="ml-2">
<el-button
plain
class="border-gray-200"
@click="searchType(item.value)"
v-for="item in [
{ label: '文章', value: 1 },
{ label: '单页', value: 2 }
]"
:key="item.value">
{{ item.label }}
</el-button>
</el-button-group>
</template>
<template #_operate="scope">
<router-link :to="'/cms/articles/create/' + scope.row.id">
<Update />
</router-link>
</template>
</catch-table>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { useDynamic } from '@/composables/useDynamic'
const { table, form, loading } = useDynamic('cms/post/dynamic/r')
const tableRef = ref()
const searchType = (val: number) => {
tableRef.value.doSearch({
type: val
})
}
</script>
表单页面
vue
<template>
<div class="w-full px-5 pt-5 pr-4 bg-white dark:bg-regal-dark">
<catch-form ref="formRef" :is-page="true" :config="{ rules: form.rules, options: form.options, api: table.api, primary: primary }" v-if="!loading" :afterSubmit="afterSubmit" />
</div>
</template>
<script lang="ts" setup>
// @ts-nocheck
import http from '@/support/http'
import { onMounted, ref, beforeMount, watch } from 'vue'
import { useDynamic } from '@/composables/useDynamic'
import router from '@/router'
const formRef = ref()
const { table, form, loading } = useDynamic('cms/post/dynamic/r')
// 作为单页使用的时候
// 编辑的时候 primary 要从页面的 route 里面获取 ID,所以这里的 primary 需要使用 ref 响应式
const primary = ref(null)
primary.value = router.currentRoute.value.params.id
const afterSubmit = () => {
router.push({ path: '/cms/articles/post' })
}
</script>
<style scoped>
:deep(.fc-form-footer) {
@apply flex justify-center !important;
}
</style>