# 模块生成

# 案例概述

在前面章节《模板介绍》中我们详细的说明了获取数据源的方式以及封装了生成每个模块文件的具体方法,绑定数据源进行模板标签替换后生成对应的模块文件并移入指定的目录中,实现的原理是获取数据表的列详细信息,包装成一个有效数据源的数组绑定到模板并进行替换,下面我们将以示例模块讲述具体的实现流程:

# 代码生成

登录后台管理系统后,打开 系统管理=>代码生成 管理模块,此时我们所看到的便是框架所集成的代码生成器模块,点击 代码生成 菜单,呈现出来的是当前数据库中的所有数据表,我们可以选择所需要生成模块的数据表点击一键生成模块确定后便可自动调用代码生成程序生成当前数据表所对应的模块,如下图所示:

  • 选择数据表

    mixureSecure

# 模块生成

上一步已经选择所需生成模块的数据表,这一步就可以生成模块文件了,点击同意生成确认框之后,程序会自动创建所有模块文件,包括:控制器文件模型文件服务类文件Vue前端文件,文件会按照设置路径存放值指定的目录,我们已数据表evt_demo2为例生成模块文件,数据表脚本如下:

CREATE TABLE `lev_demo` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '唯一性标识',
  `name` varchar(30) DEFAULT NULL COMMENT '职级名称',
  `avatar` varchar(255) DEFAULT NULL COMMENT '头像',
  `status` tinyint(1) unsigned DEFAULT 1 COMMENT '状态:1正常 2停用',
  `type` int(10) unsigned DEFAULT 1 COMMENT '类型:1京东 2淘宝 3拼多多 4唯品会',
  `is_vip` tinyint(1) unsigned DEFAULT 2 COMMENT '是否VIP:1是 2否',
  `sort` smallint(5) unsigned DEFAULT 125 COMMENT '显示顺序',
  `create_user` int(10) unsigned DEFAULT 0 COMMENT '添加人',
  `create_time` int(10) unsigned DEFAULT 0 COMMENT '添加时间',
  `update_user` int(10) unsigned DEFAULT 0 COMMENT '更新人',
  `update_time` int(10) unsigned DEFAULT 0 COMMENT '更新时间',
  `mark` tinyint(1) unsigned DEFAULT 1 COMMENT '有效标识',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COMMENT='演示管理表';

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

生成的模块文件如下:

  • 控制器文件(DemoController.php)
<?php 
// +----------------------------------------------------------------------
// | RXThinkCMF框架 [ RXThinkCMF ]
// +----------------------------------------------------------------------
// | 版权所有 2017~2020 南京RXThinkCMF研发中心
// +----------------------------------------------------------------------
// | 官方网站: http://www.rxthink.cn
// +----------------------------------------------------------------------
// | Author: 牧羊人 <1051386190@qq.com>
// +----------------------------------------------------------------------

namespace App\Http\Controllers;


use App\Services\DemoService;

/**
 * 演示管理-控制器
 * @author 牧羊人
 * @since: 2020/11/21
 * Class DemoController
 * @package App\Http\Controllers
 */
class DemoController extends Backend
{
    /**
     * 构造函数
     * @param Request $request
     * @since 2020/11/21
     * LevelController constructor.
     * @author 牧羊人
     */
    public function __construct()
    {
        parent::__construct();
        $this->service = new DemoService();
    }

	                    	            
	/**
	 * 设置是否VIP
	 * @return mixed
	 * @since 2020/11/21
	 * @author 牧羊人
	 */
	public function setIsVip()
	{
        $result = $this->service->setIsVip();
        return $result;
	}
    	                        
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  • 模型文件(DemoModel.php)
<?php 
// +----------------------------------------------------------------------
// | RXThinkCMF框架 [ RXThinkCMF ]
// +----------------------------------------------------------------------
// | 版权所有 2017~2020 南京RXThinkCMF研发中心
// +----------------------------------------------------------------------
// | 官方网站: http://www.rxthink.cn
// +----------------------------------------------------------------------
// | Author: 牧羊人 <1051386190@qq.com>
// +----------------------------------------------------------------------

namespace App\Models;

/**
 * 演示-模型
 * @author 牧羊人
 * @since 2020/11/21
 * Class DemoModel
 * @package App\Models
 */
class DemoModel extends BaseModel
{
    // 设置数据表
    protected $table = "demo";

    /**
     * 获取记录信息
     * @param int $id 记录ID
     * @return array|string
     * @author 牧羊人
     * @since: 2020/11/21
     */
    public function getInfo($id)
    {
        $info = parent::getInfo($id); // TODO: Change the autogenerated stub
        if ($info) {
                                        
            // 头像
            if ($info['avatar']) {
                $info['avatar'] = get_image_url($info['avatar']);
            }
                                                                                                                            
        }
        return $info;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  • 服务类文件(DemoService.php)
<?php 
// +----------------------------------------------------------------------
// | RXThinkCMF框架 [ RXThinkCMF ]
// +----------------------------------------------------------------------
// | 版权所有 2017~2020 南京RXThinkCMF研发中心
// +----------------------------------------------------------------------
// | 官方网站: http://www.rxthink.cn
// +----------------------------------------------------------------------
// | Author: 牧羊人 <1051386190@qq.com>
// +----------------------------------------------------------------------

namespace App\Services;


use App\Models\DemoModel;

/**
 * 演示管理-服务类
 * @author 牧羊人
 * @since: 2020/11/21
 * Class DemoService
* @package App\Services
 */
class DemoService extends BaseService
{
    /**
     * 构造函数
     * @author 牧羊人
     * @since 2020/11/21
     * LevelService constructor.
     */
    public function __construct()
    {
        $this->model = new DemoModel();
    }

	/**
     * 获取数据列表
     * @return array
     * @since 2020/11/21
     * @author 牧羊人
     */
    public function getList()
    {
        $param = request()->all();

        // 查询条件
        $map = [];
	
	    // 职级名称
        $name = isset($param['name']) ? trim($param['name']) : '';
        if ($name) {
            $map[] = ['name', 'like', "%{$name}%"];
        }
		
	    // 状态
        $status = isset($param['status']) ? (int)$param['status'] : 0;
        if ($status) {
            $map[] = ['status', '=', $status];
        }
		
	    // 类型
        $type = isset($param['type']) ? (int)$param['type'] : 0;
        if ($type) {
            $map[] = ['type', '=', $type];
        }
		
	    // 是否VIP
        $is_vip = isset($param['is_vip']) ? (int)$param['is_vip'] : 0;
        if ($is_vip) {
            $map[] = ['is_vip', '=', $is_vip];
        }
	
        return parent::getList($map); // TODO: Change the autogenerated stub
    }

	/**
     * 添加或编辑
     * @return array
     * @since 2020/11/21
     * @author 牧羊人
     */
    public function edit()
    {
        // 参数
        $data = request()->all();
	                                
		// 头像处理
        $avatar = trim($data['avatar']);
        if (strpos($avatar, "temp")) {
            $data['avatar'] = save_image($avatar, 'demo');
        } else {
            $data['avatar'] = str_replace(IMG_URL, "", $data['avatar']);
        }
                                                                                                                        
        return parent::edit($data); // TODO: Change the autogenerated stub
    }

                    	            
	/**
     * 设置是否VIP
	 * @return array
     * @since 2020/11/21
	 * @author 牧羊人
	 */
    public function setIsVip()
    {
		// 参数
        $data = request()->all();
        if (!$data['id']) {
            return message('记录ID不能为空', false);
        }
		if (!$data['is_vip']) {
            return message('记录是否VIP不能为空', false);
        }
        $error = '';
        $item = [
            'id' => $data['id'],
            'is_vip' => $data['is_vip']
        ];
        $rowId = $this->model->edit($item, $error);
        if (!$rowId) {
            return message($error, false);
        }
        return message();
    }
    	                        
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  • Vue前端文件(demo/index.vue)
<template>
  <div class="ele-body">
    <el-card shadow="never">
      <!-- 搜索表单 -->
      <el-form :model="table.where" label-width="77px" class="ele-form-search"
               @keyup.enter.native="$refs.table.reload()" @submit.native.prevent>
        <el-row :gutter="15">
          <el-col :md="6" :sm="12">
            <el-form-item label="职级名称:">
              <el-input v-model="table.where.name" placeholder="请输入职级名称" clearable/>
            </el-form-item>
          </el-col>
          <el-col :md="6" :sm="12">
            <el-form-item label="状态:">
              <el-input v-model="table.where.status" placeholder="请输入状态" clearable/>
            </el-form-item>
          </el-col>
          <el-col :md="6" :sm="12">
            <el-form-item label="类型:">
              <el-input v-model="table.where.type" placeholder="请输入类型" clearable/>
            </el-form-item>
          </el-col>
          <el-col :md="6" :sm="12">
            <el-form-item label="是否VIP:">
              <el-input v-model="table.where.is_vip" placeholder="请输入是否VIP" clearable/>
            </el-form-item>
          </el-col>
                  <el-col :md="6" :sm="12">
            <div class="ele-form-actions">
              <el-button type="primary" @click="$refs.table.reload()" icon="el-icon-search" class="ele-btn-icon">查询
              </el-button>
              <el-button @click="(table.where={})&&$refs.table.reload()">重置</el-button>
            </div>
          </el-col>
        </el-row>
      </el-form>
      <!-- 操作按钮 -->
      <div class="ele-table-tool ele-table-tool-default">
        <el-button @click="showEdit=true" type="primary" icon="el-icon-plus" class="ele-btn-icon" size="small">添加
        </el-button>
        <el-button @click="remove()" type="danger" icon="el-icon-delete" class="ele-btn-icon" size="small">批量删除
        </el-button>
      </div>
      <!-- 数据表格 -->
      <ele-data-table ref="table" :config="table" :choose.sync="choose" height="calc(100vh - 315px)" highlight-current-row>
        <template slot-scope="{index}">
          <el-table-column type="selection" width="45" align="center" fixed="left"/>
          <el-table-column type="index" :index="index" label="编号" width="60" align="center" fixed="left" show-overflow-tooltip/>
                  
          <el-table-column prop="name" label="职级名称" sortable="custom" show-overflow-tooltip min-width="120"/>
                                          
          <el-table-column prop="status" label="状态" sortable="custom" :resizable="false" min-width="120">
              <template slot-scope="{row}">
                  <el-switch v-model="row.status" @change="status(row)" :active-value="1" :inactive-value="2"/>
              </template>
          </el-table-column>
                                
          <el-table-column prop="type" label="类型" sortable="custom" show-overflow-tooltip min-width="120"/>
                                          
          <el-table-column prop="is_vip" label="是否VIP" sortable="custom" :resizable="false" min-width="120">
              <template slot-scope="{row}">
                  <el-switch v-model="row.is_vip" @change="setIsVip(row)" :active-value="1" :inactive-value="2"/>
              </template>
          </el-table-column>
                                
          <el-table-column prop="sort" label="显示顺序" sortable="custom" show-overflow-tooltip min-width="120"/>
                  
          <el-table-column label="创建时间" sortable="custom" show-overflow-tooltip min-width="160">
            <template slot-scope="{row}">{{ row.create_time*1000 | toDateString }}</template>
          </el-table-column>
          <el-table-column label="更新时间" sortable="custom" show-overflow-tooltip min-width="160">
            <template slot-scope="{row}">{{ row.update_time*1000 | toDateString }}</template>
          </el-table-column>
          <el-table-column label="操作" width="130px" align="center" :resizable="false"  fixed="right">
            <template slot-scope="{row}">
              <el-link @click="edit(row)" icon="el-icon-edit" type="primary" :underline="false">修改</el-link>
              <el-popconfirm title="确定要删除此演示吗?" @confirm="remove(row)" class="ele-action">
                <el-link slot="reference" icon="el-icon-delete" type="danger" :underline="false">删除</el-link>
              </el-popconfirm>
            </template>
          </el-table-column>
        </template>
      </ele-data-table>
    </el-card>
    <!-- 编辑弹窗 -->
    <el-dialog :title="editForm.id?'修改演示':'修改演示'" :visible.sync="showEdit" width="450px"
               @closed="editForm={}" :destroy-on-close="true" :lock-scroll="false">
      <el-form :model="editForm" ref="editForm" :rules="editRules" label-width="100px">
                          
        <el-form-item label="职级名称:" prop="name">
            <el-input v-model="editForm.name" placeholder="请输入职级名称" clearable/>
        </el-form-item>
                                              
        <el-form-item label="状态:" prop="status">
          <el-switch
                  v-model="editForm.status"
                  active-text="是"
                  inactive-text="否">
          </el-switch>
        </el-form-item>
                                              
        <el-form-item label="类型:" prop="type">
          <el-select v-model="editForm.type" placeholder="请选择类型" class="ele-block" clearable>
            <el-option
                    v-for="item in []"
                    :key="item.value"
                    :label="item.name"
                    :value="item.value">
            </el-option>
          </el-select>
        </el-form-item>
                                              
        <el-form-item label="是否VIP:" prop="is_vip">
          <el-switch
                  v-model="editForm.is_vip"
                  active-text="是"
                  inactive-text="否">
          </el-switch>
        </el-form-item>
                                                  
        <el-form-item label="显示顺序:" prop="sort">
            <el-input-number v-model="editForm.sort" controls-position="right" :min="0"
                              placeholder="请输入显示顺序" class="ele-fluid ele-text-left"/>
        </el-form-item>
                              
      </el-form>
      <div slot="footer">
        <el-button @click="showEdit=false">取消</el-button>
        <el-button type="primary" @click="save">保存</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: "SysDemo",
  data() {
    return {
      table: {url: '/demo/index', where: {}},  // 表格配置
      choose: [],  // 表格选中数据
      showEdit: false,  // 是否显示表单弹窗
      editForm: {},  // 表单数据
      editRules: {  // 表单验证规则
                        
        name: [
          {required: true, message: '请输入职级名称', trigger: 'blur'}
        ],
                          
        status: [
          {required: true, message: '请选择状态', trigger: 'blur'}
        ],
                          
        type: [
          {required: true, message: '请选择类型', trigger: 'blur'}
        ],
                          
        is_vip: [
          {required: true, message: '请选择是否VIP', trigger: 'blur'}
        ],
                          
        sort: [
          {required: true, message: '请输入显示顺序', trigger: 'blur'}
        ],
              
      },
    }
  },
  mounted() {
  },
  methods: {
    /**
     * 显示编辑
     */
    edit(row) {
      this.$http.get('/demo/info?id=' + row.id).then(res => {
        if (res.data.code === 0) {
          this.editForm = res.data.data;
          this.showEdit = true;
        } else {
          this.$message.error(res.data.msg);
        }
      }).catch(e => {
        this.$message.error(e.message);
      });
    },
    /**
     * 保存编辑
     */
    save() {
      this.$refs['editForm'].validate((valid) => {
        if (valid) {
          const loading = this.$loading({lock: true});
          this.$http.post('/demo/edit', this.editForm).then(res => {
            loading.close();
            if (res.data.code === 0) {
              this.showEdit = false;
              this.$message({type: 'success', message: res.data.msg});
              this.$refs.table.reload();
            } else {
              this.$message.error(res.data.msg);
            }
          }).catch(e => {
            loading.close();
            this.$message.error(e.message);
          });
        } else {
          return false;
        }
      });
    },
    /**
     * 刪除(批量刪除)
     */
    remove(row) {
      console.log(row)
      if (!row) {  // 批量删除
        if (this.choose.length === 0) return this.$message.error('请至少选择一条数据');
        let ids = this.choose.map(d => d.id);
        this.$confirm('确定要删除选中的演示吗?', '提示', {type: 'warning'}).then(() => {
          const loading = this.$loading({lock: true});
          this.$http.post('/demo/delete', {id: ids}).then(res => {
            loading.close();
            if (res.data.code === 0) {
              this.$message({type: 'success', message: res.data.msg});
              this.$refs.table.reload();
            } else {
              this.$message.error(res.data.msg);
            }
          }).catch(e => {
            loading.close();
            this.$message.error(e.message);
          });
        }).catch(() => 0);
      } else {  // 单个删除
        const loading = this.$loading({lock: true});
        this.$http.post('/demo/delete', {id:row.id}).then(res => {
          loading.close();
          if (res.data.code === 0) {
            this.$message({type: 'success', message: res.data.msg});
            this.$refs.table.reload();
          } else {
            this.$message.error(res.data.msg);
          }
        }).catch(e => {
          loading.close();
          this.$message.error(e.message);
        });
      }
    },
          
    /**
     * 更改状态
     */
    status(row) {
        const loading = this.$loading({lock: true});
        let params = Object.assign({}, row);
        this.$http.post("/demo/status", params).then(res => {
            loading.close();
            if (res.data.code === 0) {
                this.$message({type: 'success', message: res.data.msg});
            } else {
                row.status = !row.status ? 2 : 1;
                this.$message.error(res.data.msg);
            }
        }).catch(e => {
            loading.close();
            this.$message.error(e.message);
        });
    },
          
    /**
     * 更改是否VIP
     */
    setIsVip(row) {
        const loading = this.$loading({lock: true});
        let params = Object.assign({}, row);
        this.$http.post("/demo/setIsVip", params).then(res => {
            loading.close();
            if (res.data.code === 0) {
                this.$message({type: 'success', message: res.data.msg});
            } else {
                row.is_vip = !row.is_vip ? 2 : 1;
                this.$message.error(res.data.msg);
            }
        }).catch(e => {
            loading.close();
            this.$message.error(e.message);
        });
    },
        }
}
</script>

<style scoped>
.ele-block >>> .el-upload, .ele-block >>> .el-upload-dragger {
  width: 100%;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299

# 运行效果

以上便是生成的模块文件的内容,代码生成器在生成模块的同时,我们也同时创建了当前模块对应的菜单和权限节点,菜单默认是放入 系统工具 导航下面,如果变更层级请至菜单管理中修改,这里的前提是我们要赋予当前生成模块的菜单角色权限,如下图所示:

  • 菜单权限设置

打开 角色管理 菜单,选择 管理员角色,点击 角色权限,弹出的便是权限菜单列表,把我们刚生成的模块菜单进行勾选,提交即可;

mixureSecure

  • 模板预览

设置好菜单权限后,我们刷新当前系统,在左侧的菜单系统工具中卞可以看到模块菜单,如下图所示:

mixureSecure