vue3+webman 管理后台,自动代码生成
详细介绍
一套用于快速起新项目的基础框架,后台前端采用vue3+TS,后端采用webman
已经内置的功能包括:
1.登录
2.权限管理(用户,角色,权限,部门;可对角色授权以及对用户直接授权,权限精确到操作)
3.待办和通知消息
4.文章管理
5.操作日志,登录日志
6.配置
7.队列(基于redis)
8.websocket(可主动推消息到前端)
9.回收站功能(代码生成时自动检查是否有deleted_at字段,前端组件只需一个参数即可支持回收站功能)
10.数据导入导出(任何列表页只需要在前端组件调用时加一个参数,即可实现数据导出功能,可自定义导出表头)
11.丰富的命令行工具(根据数据表自动生成完整业务代码,本框架的特色,下面详细介绍)
演示地址
超级管理员:admin 密码:admin123
部分权限账号:yunying 密码:admin123
功能特性
1.代码生成
框架前后端的都有一套完整的扩展性极强的基础控件,很少的代码即可支持大部分场景下的增删改查,基于此再实现了一套命令,可以根据数据表通过命令直接生成对应的增删改查代码,为开发节约大量时间,让我们把更多时间用在项目设计及架构上面
例如有一张表 example, 它的字段包括
CREATE TABLE `example` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '名称',
`example_cate_id` int unsigned NOT NULL DEFAULT 0 COMMENT '分类',
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`deleted_at` datetime DEFAULT NULL,
`status` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '状态',
PRIMARY KEY (`id`) USING BTREE,
KEY `title` (`title`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
通过命令
php webman model example生成的模型文件内容如下
<?php
declare(strict_types=1);
namespace app\model;
use app\common\traits\StatusAttr;
/**
* @property int $id
* @property string $title 名称
* @property int $example_cate_id 分类
* @property ?string $created_at
* @property ?string $updated_at
* @property ?string $deleted_at
* @property int $status 状态
*/
class Example extends BaseModel
{
use StatusAttr;
protected $table = 'example';
protected $pk = 'id';
protected $field = [
'id',
'title',
'example_cate_id',
'created_at',
'updated_at',
'deleted_at',
'status',
];
protected $type = [];
}
通过命令
php webman controller example --title 示例生成的控制器文件内容如下,index接口自动支持所有字段搜索排序,columns为前端表格的表头,可根据前端组件自动调整是否支持搜索和排序;Permission注解即权限管理,对需要控制权限的方法加上注解,通过命令php webman permission example即可生成对应的权限
<?php
declare(strict_types=1);
namespace app\admin\controller;
use app\common\annotation\Permission;
use app\common\traits\CrudHelper;
use app\common\traits\Jump;
use app\common\traits\RecycleAction;
use app\common\traits\ValidateHelper;
use app\model\Example as Model;
use support\Request;
use support\Response;
class ExampleController
{
use Jump;
use CrudHelper;
use ValidateHelper;
use RecycleAction;
#[Permission(title: '示例', isMenu: 1, parentUrl: 'system')]
public function index(Request $request): Response
{
$lists = $this->tableList($request, Model::class, ['id' => 'DESC'], ['title'])
->selectData($request);
return $this->success('', [
'list' => $lists,
]);
}
#[Permission(title: '修改示例')]
public function edit(Request $request): Response
{
return $this->mEdit($request, Model::class);
}
#[Permission(title: '添加示例')]
public function add(Request $request): Response
{
return $this->mAdd($request, Model::class);
}
#[Permission(title: '删除示例')]
public function delete(Request $request): Response
{
return $this->mDelete($request, Model::class);
}
#[Permission(title: '彻底删除示例')]
public function forceDelete(Request $request): Response
{
return $this->mForceDelete($request, Model::class);
}
#[Permission(title: '恢复示例')]
public function restore(Request $request): Response
{
return $this->mRestore($request, Model::class);
}
#[Permission(title: '清空示例回收站')]
public function cleanRecycle(Request $request): Response
{
return $this->mCleanRecycle($request, Model::class);
}
public function get(Request $request): Response
{
return $this->success('', [
'detail' => Model::find(input('id')),
]);
}
#[Permission(title: '修改示例状态')]
public function status(Request $request): Response
{
$status = input('status', 0);
Model::update(['status' => $status], ['id' => $this->getInputPk($request)]);
return $this->success('修改成功', ['status' => $status]);
}
public function select(Request $request): Response
{
return $this->success('', [
'list' => $this->tableList($request, Model::class)->field('title as label,id as value')->select(),
]);
}
public function columns(Request $request): array
{
return [
[
'prop' => 'id',
'label' => 'ID',
'search' => [
'prop' => 'id_match',
],
],
[
'prop' => 'title',
'label' => '名称',
'search' => [
'prop' => 'title_like',
],
],
[
'prop' => 'example_cate_id',
'label' => '分类',
'sort' => 'example_cate_id',
'search' => [
'valueType' => 'select',
'prop' => 'example_cate_id_multiple',
'optionsConfig' => [
'url' => '/example_cate/select',
'key' => '',
],
'fieldProps' => [
'multiple' => true,
],
],
'replace' => true,
],
$this->getDateSearchColumns('created_at', '日期'),
$this->getStatusColumns('status', '状态'),
];
}
}
通过命令
php webman view example生成的vue3文件内容如下
- 列表页
<script setup lang="ts">
defineOptions({ name: "ExampleIndex" });
import ExampleAddDialog from "@/views/example/dialog/exampleAddDialog.vue";
import { ref } from "vue";
const addDialogRef = ref();
const tableRef = ref();
const handleEdit = row => {
addDialogRef.value.open(row);
};
const afterDone = () => {
tableRef.value.refresh();
};
</script>
<template>
<div>
<KylTable
ref="tableRef"
base-url="/example"
recycle
@add="handleEdit({})"
@edit="handleEdit"
/>
<ExampleAddDialog ref="addDialogRef" @done="afterDone" />
</div>
</template>
- 弹窗编辑页面
<script setup lang="ts">
import { FieldValues } from "plus-pro-components";
import { computed, ref } from "vue";
import { useOptionsStoreHook } from "@/store/modules/Options";
import { KylFormColumn } from "@/components/KylForm/types/form";
const emit = defineEmits<{
(e: "done", value: FieldValues): void;
(e: "cancel"): void;
}>();
export interface Props {
module?: string;
title?: string;
}
const props = withDefaults(defineProps<Props>(), {
module: "/example",
title: "添加/编辑"
});
const action = computed(() => {
return props.module + "/" + (state.value.id ? "edit" : "add");
});
const initValue = () => ({
id: undefined,
title: "",
example_cate_id: undefined,
status: 1
});
const state = ref<FieldValues>(initValue());
const columns: KylFormColumn[] = [
{
prop: "id",
hideInForm: true
},
{
label: "名称",
prop: "title",
required: true
},
{
label: "分类",
prop: "example_cate_id",
valueType: "select",
required: true,
options: useOptionsStoreHook().getOptionsList("/example_cate/select")
},
{
label: "状态",
prop: "status",
valueType: "status",
required: true
}
];
const visible = ref(false);
const rules = {};
const handleSubmit = (values: FieldValues) => {
useOptionsStoreHook().clearOptionsCache(props.module + "/select");
emit("done", values);
};
const open = data => {
visible.value = true;
state.value = { ...initValue(), ...data };
};
defineExpose({
open
});
</script>
<template>
<KylDialogForm
v-model:visible="visible"
v-model="state"
v-bind="$attrs"
:action="action"
:columns="columns"
:rules="rules"
:title="title"
@submit="handleSubmit"
@cancel="emit('cancel')"
/>
</template>
2.通用组件
- 后端有一套丰富的trait,包含CRUD、上传等常见操作;还有表格导入,表格导出的扩展类。
- 前端最常用两个功能:表格和表单,都有功能非常强大的组件;
- 表格组件可通过接口动态生成表头或者自定义表头,根据表头配置自动生成排序和搜索表单,支持回收站、导出、表头排序显示隐藏设置等,可覆盖90%的场景使用场景,针对特别特殊的场景也有丰富的插槽可实现任意表格显示需求。
- 表单组件是通过配置生成表单,告别繁琐的html代码,直接通过ts代码实现表单功能,可看前一部分的弹窗编辑页面的代码示例,表单支持绝大多数场景下的使用需求,基于PlusProComponents扩展了更多组件,包括数字范围输入、上传(单文件,多文件)、富文本、单值级联、segmented等等。表单组件还有一套弹窗表单组件。
安装使用
本框架只适用于二次开发,没有完整的业务功能,解压后webman目录为后端代码,admin目录为前端代码
联系方式
281313840@qq.com
后端PHP>=8.2
前端vue3+TS