sagor110090 / laravel-vue-api-crud-generator
为 Laravel 和 Vue.js 单文件组件创建 CRUD 应用程序的基本骨架。
This package is auto-updated.
Last update: 2020-12-25 20:51:39 UTC
README
概览
一个 Laravel 包,允许您为 Vue.js/Laravel 应用程序生成样板代码。只需输入数据库表的名称,它将根据该名称创建
- Laravel 模型
- Laravel 控制器(带有 get、list、create、update、delete 以及基于所选数据库表的验证)
- Laravel 路由(get、list、create、update、delete)
- 2 个 Vue.js 单文件组件,用于创建、更新、列表、删除和显示(使用 Vform & axios)
此包旨在加快后端(Laravel)和前端(Vue.js)之间的通信过程。
安装
composer require sagor110090/laravel-vue-api-crud-generator
用法
首先,您应该以通常的方式创建一个新的迁移。例如,如果创建一个 posts 表,请使用以下命令
php artisan make:migration create_posts_table
然后在迁移文件中添加您的字段,就像平常一样
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title',200);
$table->text('content')->nullable();
$table->timestamps();
});
然后运行迁移命令以创建 posts 表
php artisan migrate
完成此操作后,只需运行一个 vueapi
命令即可。将您的表名添加到命令的末尾,在这种情况下是 posts。
php artisan vueapi:generate posts
这将生成上述所有文件。
运行此命令后,使用上面的 posts
例子,它将创建以下样板文件
路由
基于 posts
数据库表,将生成以下路由
Route::get('posts', 'PostsController@list');
Route::get('posts/{id}', 'PostsController@get');
Route::post('posts', 'PostsController@create');
Route::put('posts/{id}', 'PostsController@update');
Route::delete('posts/{id}', 'PostsController@delete');
控制器
基于 posts
数据库表,将生成以下控制器
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Posts;
class PostsController extends Controller
{
public function get(Request $request, $id){
return Posts::findOrFail($id);
}
public function list(Request $request){
return Posts::get();
}
public function create(Request $request){
$validatedData = $request->validate([
'title' => 'required |max:200 ',
'content' => 'required ',
'meta_description' => 'required |max:160 ',
],[
'title.required' => 'title is a required field.',
'title.max' => 'title can only be 200 characters.',
'content.required' => 'content is a required field.',
'meta_description.required' => 'meta_description is a required field.',
'meta_description.max' => 'meta_description can only be 160 characters.',
]);
$posts = Posts::create($request->all());
return $posts;
}
public function update(Request $request, $id){
$validatedData = $request->validate([
'title' => 'required |max:200 ',
'content' => 'required ',
'meta_description' => 'required |max:160 ',
],[
'title.required' => 'title is a required field.',
'title.max' => 'title can only be 200 characters.',
'content.required' => 'content is a required field.',
'meta_description.required' => 'meta_description is a required field.',
'meta_description.max' => 'meta_description can only be 160 characters.',
]);
$posts = Posts::findOrFail($id);
$input = $request->all();
$posts->fill($input)->save();
return $posts;
}
public function delete(Request $request, $id){
$posts = Posts::findOrFail($id);
$posts->delete();
}
}
?>
模型
基于 posts
数据库表,将生成以下模型
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Posts extends Model
{
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $guarded = [
'id'
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
''
];
}?>
Vue(列表模板)
基于 posts
数据库表,将生成以下 Vue.js 列表单文件组件(Posts-list.vue)
<template lang="html">
<div class="posts">
<div class="half">
<h1>Create post</h1>
<form @submit.prevent="createPost">
<div class="form-group">
<input type="hidden" v-model="form.id"></input>
</div>
<div class="form-group">
<label>title</label>
<input type="text" v-model="form.title" maxlength="200" ></input>
<has-error :form="form" field="title"></has-error>
</div>
<div class="form-group">
<label>content</label>
<textarea v-model="form.content" ></textarea>
<has-error :form="form" field="content"></has-error>
</div>
<div class="form-group">
<label>meta_description</label>
<input type="text" v-model="form.meta_description" maxlength="160" ></input>
<has-error :form="form" field="meta_description"></has-error>
</div>
<div class="form-group">
<input type="hidden" v-model="form.created_at"></input>
</div>
<div class="form-group">
<input type="hidden" v-model="form.updated_at"></input>
</div>
<div class="form-group">
<button class="button" type="submit" :disabled="form.busy" name="button">{{ (form.busy) ? 'Please wait...' : 'Submit'}}</button>
</div>
</form>
</div><!-- End first half -->
<div class="half">
<h1>List posts</h1>
<ul v-if="posts.length > 0">
<li v-for="(post,index) in posts" :key="post.id">
<router-link :to="'/post/'+post.id">
post {{ index }}
<button @click.prevent="deletePost(post,index)" type="button" :disabled="form.busy" name="button">{{ (form.busy) ? 'Please wait...' : 'Delete'}}</button>
</router-link>
</li>
</ul>
<span v-else-if="!posts">Loading...</span>
<span v-else>No posts exist</span>
</div><!-- End 2nd half -->
</div>
</template>
<script>
import { Form, HasError, AlertError } from 'vform'
export default {
name: 'Post',
components: {HasError},
data: function(){
return {
posts : false,
form: new Form({
"id" : "",
"title" : "",
"content" : "",
"meta_description" : "",
"created_at" : "",
"updated_at" : "",
})
}
},
created: function(){
this.listPosts();
},
methods: {
listPosts: function(){
var that = this;
this.form.get('/posts').then(function(response){
that.posts = response.data;
})
},
createPost: function(){
var that = this;
this.form.post('/posts').then(function(response){
that.posts.push(response.data);
})
},
deletePost: function(post, index){
var that = this;
this.form.delete('/posts/'+post.id).then(function(response){
that.posts.splice(index,1);
})
}
}
}
</script>
<style lang="less">
.posts{
margin:0 auto;
width:700px;
display:flex;
.half{
flex:1;
&:first-of-type{
margin-right:20px;
}
}
form{
.form-group{
margin-bottom:20px;
label{
display:block;
margin-bottom:5px;
text-transform: capitalize;
}
input[type="text"],input[type="number"],textarea{
width:100%;
max-width:100%;
min-width:100%;
padding:10px;
border-radius:3px;
border:1px solid silver;
font-size:1rem;
&:focus{
outline:0;
border-color:blue;
}
}
.invalid-feedback{
color:red;
&::first-letter{
text-transform:capitalize;
}
}
}
.button{
appearance: none;
background: #3bdfd9;
font-size: 1rem;
border: 0px;
padding: 10px 20px;
border-radius: 3px;
font-weight: bold;
&:hover{
cursor:pointer;
background: darken(#3bdfd9,10);
}
}
}
}
</style>
Vue(单个模板)
基于 posts
数据库表,将生成以下 Vue.js 单文件组件(Posts-single.vue)
<template lang="html">
<div class="PostSingle">
<h1>Update Post</h1>
<form @submit.prevent="updatePost" v-if="loaded">
<router-link to="/posts">< Back to posts</router-link>
<div class="form-group">
<input type="hidden" v-model="form.id"></input>
</div>
<div class="form-group">
<label>title</label>
<input type="text" v-model="form.title" maxlength="200" ></input>
<has-error :form="form" field="title"></has-error>
</div>
<div class="form-group">
<label>content</label>
<textarea v-model="form.content" ></textarea>
<has-error :form="form" field="content"></has-error>
</div>
<div class="form-group">
<label>meta_description</label>
<input type="text" v-model="form.meta_description" maxlength="160" ></input>
<has-error :form="form" field="meta_description"></has-error>
</div>
<div class="form-group">
<input type="hidden" v-model="form.created_at"></input>
</div>
<div class="form-group">
<input type="hidden" v-model="form.updated_at"></input>
</div>
<div class="form-group">
<button class="button" type="submit" :disabled="form.busy" name="button">{{ (form.busy) ? 'Please wait...' : 'Update'}}</button>
<button @click.prevent="deletePost">{{ (form.busy) ? 'Please wait...' : 'Delete'}}</button>
</div>
</form>
<span v-else>Loading post...</span>
</div>
</template>
<script>
import { Form, HasError, AlertError } from 'vform'
export default {
name: 'Post',
components: {HasError},
data: function(){
return {
loaded: false,
form: new Form({
"id" : "",
"title" : "",
"content" : "",
"meta_description" : "",
"created_at" : "",
"updated_at" : "",
})
}
},
created: function(){
this.getPost();
},
methods: {
getPost: function(Post){
var that = this;
this.form.get('/posts/'+this.$route.params.id).then(function(response){
that.form.fill(response.data);
that.loaded = true;
}).catch(function(e){
if (e.response && e.response.status == 404) {
that.$router.push('/404');
}
});
},
updatePost: function(){
var that = this;
this.form.put('/posts/'+this.$route.params.id).then(function(response){
that.form.fill(response.data);
})
},
deletePost: function(){
var that = this;
this.form.delete('/posts/'+this.$route.params.id).then(function(response){
that.form.fill(response.data);
that.$router.push('/posts');
})
}
}
}
</script>
<style lang="less">
.PostSingle{
margin:0 auto;
width:700px;
form{
.form-group{
margin-bottom:20px;
label{
display:block;
margin-bottom:5px;
text-transform: capitalize;
}
input[type="text"],input[type="number"],textarea{
width:100%;
max-width:100%;
min-width:100%;
padding:10px;
border-radius:3px;
border:1px solid silver;
font-size:1rem;
&:focus{
outline:0;
border-color:blue;
}
}
.button{
appearance: none;
background: #3bdfd9;
font-size: 1rem;
border: 0px;
padding: 10px 20px;
border-radius: 3px;
font-weight: bold;
&:hover{
cursor:pointer;
background: darken(#3bdfd9,10);
}
}
.invalid-feedback{
color:red;
&::first-letter{
text-transform:capitalize;
}
}
}
}
}
</style>
配置
以下是配置设置及其默认值。
<?php
return [
'model_dir' => base_path('app'),
'controller_dir' => base_path('app/Http/Controllers'),
'vue_files_dir' => base_path('resources/views/vue'),
'routes_dir' => base_path('routes'),
'routes_file' => 'api.php'
];
?>
要将配置文件复制到您的 Laravel 工作项目,请输入以下 artisan 命令
php artisan vendor:publish --provider="sagor110090\vueApi\vueApiServiceProvider" --tag="config"
model_dir
指定生成的模型文件应存储的位置
controller_dir
指定生成的控制器文件应存储的位置
vue_files_dir
指定Vue单文件模板应存储的位置
vue_url_prefix
指定应添加到视图文件URL的前缀。默认为/api
,例如/api/posts
routes_dir
指定路由目录的位置
routes_file
指定路由文件的名字
自定义模板
如果您使用其他前端框架如React或想要调整模板的结构,则可以通过将其发布到您的Laravel工作项目来自定义模板
`php artisan vendor:publish --provider="lummy\vueApi\vueApiServiceProvider" --tag="templates"`
它们将出现在以下位置
\resources\views\vendor\vueApi
模板中的变量
每个模板文件传递一个包含以下字段的数据数组
$data['singular']
数据库表的单一名称,例如Post
$data['plural']
数据库表的复数名称,例如Posts
$data['singular_lower']
数据库表的单一名称(小写),例如post
$data['plural_lower']
数据库表的复数名称(小写),例如posts
$data['fields']
包含模型字段数组的数组。
- name(字段名称)
- type(mysql varchar,int等)
- simplified_type(text,textarea,number)
- required(字段是否必需)
- max(字符的最大数量)
其他注意事项
我仅在Laravel MYSQL驱动程序上进行了测试,因此不确定它是否在其他数据库上工作。
在Vue.js文件中,假设路由为:使用posts示例。您可以从生成的模板轻松配置这些路由
/posts(Posts-list.vue)/posts/{id}(Posts-single.vue)
请随时联系我提供反馈或建议 https://github.com/sagor110090