feat:系统模块初始化

This commit is contained in:
JaguarJack
2023-05-15 13:23:32 +08:00
parent b8c4c90da7
commit 2a6d65d4e7
13 changed files with 812 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace Modules\System\Http\Controllers;
use Catch\Base\CatchController as Controller;
use Modules\System\Models\Dictionary;
use Illuminate\Http\Request;
class DictionaryController extends Controller
{
public function __construct(
protected readonly Dictionary $model
){}
/**
* @return mixed
*/
public function index(): mixed
{
return $this->model->getList();
}
/**
* @param Request $request
* @return mixed
*/
public function store(Request $request)
{
return $this->model->storeBy($request->all());
}
/**
* @param $id
* @return mixed
*/
public function show($id)
{
return $this->model->firstBy($id);
}
/**
* @param Request $request
* @param $id
* @return mixed
*/
public function update($id, Request $request)
{
return $this->model->updateBy($id, $request->all());
}
/**
* @param $id
* @return mixed
*/
public function destroy($id)
{
$dictionary = $this->model->find($id);
if ($this->model->deleteBy($id)) {
return $dictionary->values()->delete();
}
return false;
}
public function enable($id)
{
return $this->model->toggleBy($id);
}
}

View File

@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Modules\System\Http\Controllers;
use Catch\Base\CatchController as Controller;
use Modules\System\Models\DictionaryValues;
use Illuminate\Http\Request;
class DictionaryValuesController extends Controller
{
public function __construct(
protected readonly DictionaryValues $model
){}
/**
* @return mixed
*/
public function index(): mixed
{
return $this->model->getList();
}
/**
* @param Request $request
* @return mixed
*/
public function store(Request $request)
{
return $this->model->storeBy($request->all());
}
/**
* @param $id
* @return mixed
*/
public function show($id)
{
return $this->model->firstBy($id);
}
/**
* @param Request $request
* @param $id
* @return mixed
*/
public function update($id, Request $request)
{
return $this->model->updateBy($id, $request->all());
}
/**
* @param $id
* @return mixed
*/
public function destroy($id)
{
return $this->model->deleteBy($id);
}
public function enable($id)
{
return $this->model->toggleBy($id);
}
}

View File

@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace Modules\System\Models;
use Catch\Base\CatchModel as Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* @property $id
* @property $name
* @property $key
* @property $status
* @property $description
* @property $creator_id
* @property $created_at
* @property $updated_at
* @property $deleted_at
*/
class Dictionary extends Model
{
protected $table = 'system_dictionary';
protected $fillable = [ 'id', 'name', 'key', 'status', 'description', 'creator_id', 'created_at', 'updated_at', 'deleted_at' ];
/**
* @var array
*/
protected array $fields = ['id','name','key','status','description','created_at','updated_at'];
/**
* @var array
*/
protected array $form = ['name','key','status','description'];
/**
* @var array
*/
public array $searchable = [
'name' => 'like',
'key' => 'like',
'status' => '=',
];
/**
* 字典值集合
*
* @return HasMany
*/
public function values(): HasMany
{
return $this->hasMany(DictionaryValues::class, 'dic_id', 'id');
}
}

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Modules\System\Models;
use Catch\Base\CatchModel as Model;
/**
* @property $id
* @property $dic_id
* @property $label
* @property $value
* @property $sort
* @property $status
* @property $description
* @property $creator_id
* @property $created_at
* @property $updated_at
* @property $deleted_at
*/
class DictionaryValues extends Model
{
protected $table = 'system_dictionary_values';
protected $fillable = [ 'id', 'dic_id', 'label', 'value', 'sort', 'status', 'description', 'creator_id', 'created_at', 'updated_at', 'deleted_at' ];
/**
* @var array
*/
protected array $fields = ['id','label','value','sort','status','description','created_at','updated_at'];
/**
* @var array
*/
protected array $form = ['dic_id', 'label','value','sort','description'];
/**
* @var array
*/
public array $searchable = [
'dic_ids' => '=',
'label' => 'like',
'status' => '=',
];
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Modules\System\Providers;
use Catch\CatchAdmin;
use Catch\Providers\CatchModuleServiceProvider;
class SystemServiceProvider extends CatchModuleServiceProvider
{
/**
* route path
*
* @return string
*/
public function moduleName(): string
{
// TODO: Implement path() method.
return 'system';
}
}

View File

@@ -0,0 +1,41 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('system_dictionary', function (Blueprint $table) {
$table->id();
$table->string('name', 100)->comment('字典名称');
$table->string('key')->comment('字典 key');
$table->tinyInteger('status')->default(1)->comment('状态 1 启用 2 禁用');
$table->string('description', 1000)->comment('备注')->default('');
$table->creatorId();
$table->createdAt();
$table->updatedAt();
$table->deletedAt();
$table->engine='InnoDB';
$table->comment('字段管理');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('system_dictionary');
}
};

View File

@@ -0,0 +1,43 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('system_dictionary_values', function (Blueprint $table) {
$table->id();
$table->integer('dic_id')->comment('字典ID');
$table->string('label')->comment('值名称');
$table->tinyInteger('value')->comment('对应值');
$table->integer('sort')->default(0)->comment('排序');
$table->tinyInteger('status')->default(1)->comment('状态 1 正常 2 禁用');
$table->string('description', 1000)->comment('描述')->default('');
$table->creatorId();
$table->createdAt();
$table->updatedAt();
$table->deletedAt();
$table->engine='InnoDB';
$table->comment('字典对应值');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('system_dictionary_values');
}
};

View File

@@ -0,0 +1,193 @@
<?php
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
return new class extends Seeder
{
/**
* Run the seeder.
*
* @return void
*/
public function run(): void
{
$menus = $this->menus();
importTreeData($menus, 'permissions');
}
public function menus(): array
{
return array (
0 =>
array (
'id' => 96,
'parent_id' => 0,
'permission_name' => '系统管理',
'route' => '/system',
'icon' => 'server-stack',
'module' => 'system',
'permission_mark' => '',
'component' => '',
'redirect' => NULL,
'keepalive' => 1,
'type' => 1,
'hidden' => 1,
'sort' => 1,
'active_menu' => '',
'creator_id' => 1,
'created_at' => 1683535826,
'updated_at' => 1683535826,
'deleted_at' => 0,
),
1 =>
array (
'id' => 97,
'parent_id' => 96,
'permission_name' => '字典管理',
'route' => 'dictionary',
'icon' => '',
'module' => 'system',
'permission_mark' => 'dictionary',
'component' => '/System/views/dictionary/index.vue',
'redirect' => '',
'keepalive' => 1,
'type' => 2,
'hidden' => 1,
'sort' => 1,
'active_menu' => '',
'creator_id' => 1,
'created_at' => 1683535863,
'updated_at' => 1683535874,
'deleted_at' => 0,
),
2 =>
array (
'id' => 103,
'parent_id' => 97,
'permission_name' => '删除',
'route' => '',
'icon' => '',
'module' => 'system',
'permission_mark' => 'dictionary@destroy',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 3,
'hidden' => 1,
'sort' => 5,
'active_menu' => '',
'creator_id' => 1,
'created_at' => 1683535980,
'updated_at' => 1683535980,
'deleted_at' => 0,
),
3 =>
array (
'id' => 99,
'parent_id' => 97,
'permission_name' => '列表',
'route' => '',
'icon' => '',
'module' => 'system',
'permission_mark' => 'dictionary@index',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 3,
'hidden' => 1,
'sort' => 1,
'active_menu' => '',
'creator_id' => 1,
'created_at' => 1683535980,
'updated_at' => 1683535980,
'deleted_at' => 0,
),
4 =>
array (
'id' => 101,
'parent_id' => 97,
'permission_name' => '读取',
'route' => '',
'icon' => '',
'module' => 'system',
'permission_mark' => 'dictionary@show',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 3,
'hidden' => 1,
'sort' => 3,
'active_menu' => '',
'creator_id' => 1,
'created_at' => 1683535980,
'updated_at' => 1683535980,
'deleted_at' => 0,
),
5 =>
array (
'id' => 100,
'parent_id' => 97,
'permission_name' => '新增',
'route' => '',
'icon' => '',
'module' => 'system',
'permission_mark' => 'dictionary@store',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 3,
'hidden' => 1,
'sort' => 2,
'active_menu' => '',
'creator_id' => 1,
'created_at' => 1683535980,
'updated_at' => 1683535980,
'deleted_at' => 0,
),
6 =>
array (
'id' => 102,
'parent_id' => 97,
'permission_name' => '更新',
'route' => '',
'icon' => '',
'module' => 'system',
'permission_mark' => 'dictionary@update',
'component' => '',
'redirect' => '',
'keepalive' => 1,
'type' => 3,
'hidden' => 1,
'sort' => 4,
'active_menu' => '',
'creator_id' => 1,
'created_at' => 1683535980,
'updated_at' => 1683535980,
'deleted_at' => 0,
),
7 =>
array (
'id' => 98,
'parent_id' => 96,
'permission_name' => '字典值管理',
'route' => 'dictionary/values/:id',
'icon' => '',
'module' => 'system',
'permission_mark' => 'dictionaryValues',
'component' => '/System/views/dictionaryValues/index.vue',
'redirect' => '',
'keepalive' => 2,
'type' => 2,
'hidden' => 2,
'sort' => 1,
'active_menu' => '/system/dictionary',
'creator_id' => 1,
'created_at' => 1683535961,
'updated_at' => 1683593856,
'deleted_at' => 0,
),
);
}
};

View File

@@ -0,0 +1,17 @@
<?php
use Illuminate\Support\Facades\Route;
use Modules\System\Http\Controllers\DictionaryController;
use Modules\System\Http\Controllers\DictionaryValuesController;
Route::prefix('system')->group(function(){
Route::apiResource('dictionary', DictionaryController::class);
Route::put('dictionary/enable/{id}', [DictionaryController::class, 'enable']);
Route::apiResource('dic/values', DictionaryValuesController::class);
Route::put('dic/values/enable/{id}', [DictionaryValuesController::class, 'enable']);
//next
});

View File

@@ -0,0 +1,56 @@
<template>
<el-form :model="formData" label-width="120px" ref="form" v-loading="loading" class="pr-4">
<el-form-item
label="字典名称"
prop="name"
:rules="[
{
required: true,
message: '字典名称必须填写',
},
]"
>
<el-input v-model="formData.name" name="name" clearable />
</el-form-item>
<el-form-item
label="字典键名"
prop="key"
:rules="[
{
required: true,
message: '字典键名必须填写',
},
]"
>
<el-input v-model="formData.key" name="key" clearable />
</el-form-item>
<el-form-item label="字典描述" prop="description">
<el-input v-model="formData.description" name="description" clearable type="textarea" />
</el-form-item>
<div class="flex justify-end">
<el-button type="primary" @click="submitForm(form)">{{ $t('system.confirm') }}</el-button>
</div>
</el-form>
</template>
<script lang="ts" setup>
import { useCreate } from '/admin/composables/curd/useCreate'
import { useShow } from '/admin/composables/curd/useShow'
import { onMounted } from 'vue'
const props = defineProps({
primary: String | Number,
api: String,
})
const { formData, form, loading, submitForm, close } = useCreate(props.api, props.primary)
if (props.primary) {
useShow(props.api, props.primary, formData)
}
const emit = defineEmits(['close'])
onMounted(() => {
close(() => emit('close'))
})
</script>

View File

@@ -0,0 +1,73 @@
<template>
<div>
<Search :search="search" :reset="reset">
<template v-slot:body>
<el-form-item label="字典名称" prop="name">
<el-input v-model="query.name" name="name" clearable />
</el-form-item>
<el-form-item label="字典键名" prop="key">
<el-input v-model="query.key" name="key" clearable />
</el-form-item>
<el-form-item label="字典状态" prop="status">
<el-input v-model="query.status" name="status" clearable />
</el-form-item>
</template>
</Search>
<div class="table-default">
<Operate :show="open" />
<el-table :data="tableData" class="mt-3" v-loading="loading">
<el-table-column prop="id" label="ID" width="100" />
<el-table-column prop="name" label="字典名称" />
<el-table-column prop="key" label="字典键名">
<template #default="scope">
<router-link :to="{ path: '/system/dictionary/values/' + scope.row.id }">
<el-text type="primary">{{ scope.row.key }}</el-text>
</router-link>
</template>
</el-table-column>
<el-table-column prop="status" label="字典状态">
<template #default="scope">
<Status v-model="scope.row.status" :id="scope.row.id" :api="api" />
</template>
</el-table-column>
<el-table-column prop="description" label="字典描述" />
<el-table-column label="操作" width="300">
<template #default="scope">
<Update @click="open(scope.row.id)" />
<Destroy @click="destroy(api, scope.row.id)" />
<router-link :to="{ path: '/system/dictionary/values/' + scope.row.id }">
<Show text="列表" class="ml-3" />
</router-link>
</template>
</el-table-column>
</el-table>
<Paginate />
</div>
<Dialog v-model="visible" :title="title" destroy-on-close>
<Create @close="close(reset)" :primary="id" :api="api" />
</Dialog>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted } from 'vue'
import Create from './create.vue'
import { useGetList } from '/admin/composables/curd/useGetList'
import { useDestroy } from '/admin/composables/curd/useDestroy'
import { useOpen } from '/admin/composables/curd/useOpen'
const api = 'system/dictionary'
const { data, query, search, reset, loading } = useGetList(api)
const { destroy, deleted } = useDestroy()
const { open, close, title, visible, id } = useOpen()
const tableData = computed(() => data.value?.data)
onMounted(() => {
search()
deleted(reset)
})
</script>

View File

@@ -0,0 +1,65 @@
<template>
<el-form :model="formData" label-width="120px" ref="form" v-loading="loading" class="pr-4">
<el-form-item
label="字典值名"
prop="label"
:rules="[
{
required: true,
message: '字典值名必须填写',
},
]"
>
<el-input v-model="formData.label" name="label" clearable />
</el-form-item>
<el-form-item
label="字典键值"
prop="value"
:rules="[
{
required: true,
message: '字典键值必须填写',
},
]"
>
<el-input-number v-model="formData.value" name="value" clearable :min="1" />
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="formData.sort" name="sort" :min="1" />
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input v-model="formData.description" name="description" clearable type="textarea" />
</el-form-item>
<div class="flex justify-end">
<el-button type="primary" @click="submitForm(form)">{{ $t('system.confirm') }}</el-button>
</div>
</el-form>
</template>
<script lang="ts" setup>
import { useCreate } from '/admin/composables/curd/useCreate'
import { useShow } from '/admin/composables/curd/useShow'
import { onMounted } from 'vue'
import router from '/admin/router'
const props = defineProps({
primary: String | Number,
api: String,
})
const { formData, form, loading, submitForm, close } = useCreate(props.api, props.primary)
// 默认值
formData.value.value = 1
formData.value.sort = 1
formData.value.dic_id = router.currentRoute.value.params.id
if (props.primary) {
useShow(props.api, props.primary, formData)
}
const emit = defineEmits(['close'])
onMounted(() => {
close(() => emit('close'))
})
</script>

View File

@@ -0,0 +1,64 @@
<template>
<div>
<Search :search="search" :reset="reset">
<template v-slot:body>
<el-form-item label="字典值名" prop="label">
<el-input v-model="query.label" name="label" clearable />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-input v-model="query.status" name="status" clearable />
</el-form-item>
</template>
</Search>
<div class="table-default">
<Operate :show="open" />
<el-table :data="tableData" class="mt-3" v-loading="loading">
<el-table-column prop="id" label="ID" />
<el-table-column prop="label" label="字典值名称" />
<el-table-column prop="value" label="字典键值" />
<el-table-column prop="sort" label="排序" />
<el-table-column prop="status" label="状态">
<template #default="scope">
<Status v-model="scope.row.status" :id="scope.row.id" :api="api" />
</template>
</el-table-column>
<el-table-column prop="description" label="描述" />
<el-table-column label="操作" width="200">
<template #default="scope">
<Update @click="open(scope.row.id)" />
<Destroy @click="destroy(api, scope.row.id)" />
</template>
</el-table-column>
</el-table>
<Paginate />
</div>
<Dialog v-model="visible" :title="title" destroy-on-close>
<Create @close="close(reset)" :primary="id" :api="api" />
</Dialog>
</div>
</template>
<script lang="ts" setup>
import { computed, onMounted } from 'vue'
import Create from './create.vue'
import { useGetList } from '/admin/composables/curd/useGetList'
import { useDestroy } from '/admin/composables/curd/useDestroy'
import { useOpen } from '/admin/composables/curd/useOpen'
import router from '/admin/router'
const api = 'system/dic/values'
const { data, query, search, reset, loading } = useGetList(api)
query.value.dic_id = router.currentRoute.value.params.id
const { destroy, deleted } = useDestroy()
const { open, close, title, visible, id } = useOpen()
const tableData = computed(() => data.value?.data)
onMounted(() => {
search()
deleted(reset)
})
</script>