初始化本地仓库
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
import request from '@/utils/http';
|
||||
|
||||
/**
|
||||
* {{pluginName}} 插件 API
|
||||
*/
|
||||
export default {
|
||||
/**
|
||||
* 列表 API
|
||||
* @param params 查询参数
|
||||
* @returns 响应数据
|
||||
*/
|
||||
async test(params = {}) {
|
||||
return request.get<{ msg?: string; data?: unknown }>({
|
||||
url: '/{{pluginKey}}/index',
|
||||
params
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"{{pluginName}}": {
|
||||
"title": "{{pluginTitle}}",
|
||||
"description": "{{pluginDescription}}",
|
||||
"list": "列表",
|
||||
"add": "添加",
|
||||
"edit": "编辑",
|
||||
"delete": "删除",
|
||||
"detail": "详情",
|
||||
"save": "保存",
|
||||
"cancel": "取消",
|
||||
"search": "搜索",
|
||||
"reset": "重置",
|
||||
"confirm": "确认",
|
||||
"success": "操作成功",
|
||||
"error": "操作失败",
|
||||
"loading": "加载中..."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { AppRouteRecord } from '@/types/router'
|
||||
import { RoutesAlias } from '@/router/routesAlias'
|
||||
|
||||
export default {
|
||||
path: '/{{pluginName}}',
|
||||
name: '{{camelPluginName}}',
|
||||
component: RoutesAlias.Layout,
|
||||
meta: {
|
||||
title: '{{pluginTitle}}',
|
||||
icon: 'ri:plugin-line',
|
||||
module: '{{pluginName}}'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
name: '{{camelPluginName}}Index',
|
||||
component: '/{{pluginKey}}/index/index',
|
||||
meta: {
|
||||
title: '首页',
|
||||
icon: 'ri:home-line',
|
||||
keepAlive: false,
|
||||
module: '{{pluginName}}'
|
||||
}
|
||||
}
|
||||
]
|
||||
} as AppRouteRecord
|
||||
@@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div class="{{pluginName}}-container">
|
||||
<div class="plugin-header">
|
||||
<h1>{{ $t('{{pluginName}}.title') }}</h1>
|
||||
<p>{{ $t('{{pluginName}}.description') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="plugin-content">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>{{ $t('{{pluginName}}.card_title') }}</span>
|
||||
<el-button type="primary" @click="fetchTestData">
|
||||
{{ $t('{{pluginName}}.refresh_btn') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-loading="loading" class="card-body">
|
||||
<div v-if="error" class="error-message">
|
||||
<el-alert
|
||||
:title="error"
|
||||
type="error"
|
||||
show-icon
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-else-if="testData" class="plugin-data">
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="测试消息">
|
||||
{{ testData.msg }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="数据">
|
||||
{{ testData.data }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div v-else class="empty-state">
|
||||
<el-empty description="暂无数据" />
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import pluginApi from '../../../api/index';
|
||||
|
||||
export default defineComponent({
|
||||
name: '{{camelPluginName}}View',
|
||||
setup() {
|
||||
const loading = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
const testData = ref<{ msg?: string; data?: unknown } | null>(null);
|
||||
|
||||
const fetchTestData = async () => {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
const response = await pluginApi.test();
|
||||
testData.value = response;
|
||||
} catch (err: unknown) {
|
||||
error.value = err instanceof Error ? err.message : '网络错误';
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 初始加载数据
|
||||
fetchTestData();
|
||||
|
||||
return {
|
||||
loading,
|
||||
error,
|
||||
testData,
|
||||
fetchTestData
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.{{pluginName}}-container {
|
||||
padding: 20px;
|
||||
min-height: 80vh;
|
||||
}
|
||||
|
||||
.plugin-header {
|
||||
margin-bottom: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.plugin-header h1 {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.plugin-header p {
|
||||
font-size: 16px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.plugin-content {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.plugin-data {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.plugin-data pre {
|
||||
background-color: #f5f7fa;
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
overflow-x: auto;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
min-height: 300px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'name' => '{{pluginName}}',
|
||||
'title' => '{{pluginTitle}}',
|
||||
'type' => 'madong',
|
||||
'description' => '{{pluginDescription}}',
|
||||
'author' => 'Your Name',
|
||||
'email' => 'your.email@example.com',
|
||||
'version' => '1.0.0',
|
||||
// Composer 依赖
|
||||
'require' => [
|
||||
'composer' => [],
|
||||
],
|
||||
// NPM 依赖
|
||||
'npm_require' => [
|
||||
'admin' => [],
|
||||
'web' => [],
|
||||
],
|
||||
|
||||
// 卸载配置
|
||||
'uninstall' => [
|
||||
'undeletable' => false, // 是否不可删除(true: 系统内置插件不可删除, false: 可删除)
|
||||
'drop_tables' => true, // 删除数据表
|
||||
'remove_dependencies' => false, // 移除合并的依赖
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'enable' => true,
|
||||
'debug' => true,
|
||||
'controller_suffix' => 'Controller',
|
||||
'controller_reuse' => false,
|
||||
'version' => '1.0.0',
|
||||
];
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* {{camelPluginName}} 控制器
|
||||
*/
|
||||
|
||||
namespace plugin\{{pluginName}}\app\adminapi\controller;
|
||||
|
||||
use app\adminapi\middleware\OperationMiddleware;
|
||||
use app\adminapi\middleware\PermissionMiddleware;
|
||||
use core\tool\Json;
|
||||
use madong\swagger\annotation\response\DataResponse;
|
||||
use madong\swagger\annotation\response\SimpleResponse;
|
||||
use madong\swagger\attribute\Permission;
|
||||
use madong\swagger\attribute\AllowAnonymous;
|
||||
use OpenApi\Attributes as OA;
|
||||
use support\annotation\Middleware;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
|
||||
#[Middleware(OperationMiddleware::class, PermissionMiddleware::class)]
|
||||
class {{camelPluginName}}Controller
|
||||
{
|
||||
#[OA\Get(
|
||||
path: '/{{pluginKey}}/index',
|
||||
summary: '获取列表',
|
||||
tags: ['{{pluginName}}']
|
||||
)]
|
||||
#[DataResponse(description: '获取成功')]
|
||||
#[Permission(code: '{{pluginName}}:index', description: '列表权限')]
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
return Json::success('获取成功', []);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/{{pluginKey}}/create',
|
||||
summary: '创建',
|
||||
tags: ['{{pluginName}}']
|
||||
)]
|
||||
#[SimpleResponse(description: '创建成功')]
|
||||
#[Permission(code: '{{pluginName}}:create', description: '创建权限')]
|
||||
public function create(Request $request): Response
|
||||
{
|
||||
return Json::success('创建成功');
|
||||
}
|
||||
|
||||
#[OA\Get(
|
||||
path: '/{{pluginKey}}/info',
|
||||
summary: '详情',
|
||||
tags: ['{{pluginName}}']
|
||||
)]
|
||||
#[DataResponse(description: '获取成功')]
|
||||
#[Permission(code: '{{pluginName}}:info', description: '详情权限')]
|
||||
public function info(Request $request): Response
|
||||
{
|
||||
return Json::success('获取成功', []);
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/{{pluginKey}}/update',
|
||||
summary: '更新',
|
||||
tags: ['{{pluginName}}']
|
||||
)]
|
||||
#[SimpleResponse(description: '更新成功')]
|
||||
#[Permission(code: '{{pluginName}}:update', description: '更新权限')]
|
||||
public function update(Request $request): Response
|
||||
{
|
||||
return Json::success('更新成功');
|
||||
}
|
||||
|
||||
#[OA\Post(
|
||||
path: '/{{pluginKey}}/delete',
|
||||
summary: '删除',
|
||||
tags: ['{{pluginName}}']
|
||||
)]
|
||||
#[SimpleResponse(description: '删除成功')]
|
||||
#[Permission(code: '{{pluginName}}:delete', description: '删除权限')]
|
||||
public function delete(Request $request): Response
|
||||
{
|
||||
return Json::success('删除成功');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\{{pluginName}};
|
||||
|
||||
use core\plugin\PluginInstall as BasePluginInstall;
|
||||
|
||||
/**
|
||||
* 插件安装类
|
||||
* 继承 PluginInstall 基类,自动处理:
|
||||
* - 数据库迁移 (resource/database/migrations/)
|
||||
* - 种子数据 (resource/database/seeds/)
|
||||
*
|
||||
* 菜单需要按需导入或卸载;模板在安装时导入,物理删除由删除插件阶段统一处理:
|
||||
* - $this->importPluginMenus() - 导入菜单
|
||||
* - $this->importTemplates() - 复制模板
|
||||
* - $this->uninstallPluginMenus() - 卸载菜单
|
||||
*/
|
||||
class Install extends BasePluginInstall
|
||||
{
|
||||
/**
|
||||
* 安装前回调
|
||||
*/
|
||||
protected function beforeInstall(string $version): void
|
||||
{
|
||||
$this->output(" 🔄 Running beforeInstall...\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* 安装后回调 - 按需导入菜单和模板
|
||||
*/
|
||||
protected function afterInstall(string $version): void
|
||||
{
|
||||
$this->output(" 🔄 Running afterInstall...\n");
|
||||
|
||||
// 导入菜单
|
||||
$this->importPluginMenus();
|
||||
|
||||
// 复制模板资源
|
||||
$this->importTemplates();
|
||||
}
|
||||
|
||||
/**
|
||||
* 卸载前回调
|
||||
*/
|
||||
protected function beforeUninstall(string $version): void
|
||||
{
|
||||
$this->output(" 🔄 Running beforeUninstall...\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* 卸载后回调 - 清理菜单
|
||||
*/
|
||||
protected function afterUninstall(string $version): void
|
||||
{
|
||||
$this->output(" 🔄 Running afterUninstall...\n");
|
||||
// 卸载菜单
|
||||
$this->uninstallPluginMenus();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 后台菜单配置
|
||||
* 安装时会自动加载
|
||||
*/
|
||||
|
||||
return [
|
||||
[
|
||||
'name' => '{{pluginTitle}}',
|
||||
'code' => '{{pluginKey}}',
|
||||
'app' => '{{pluginName}}',
|
||||
'path' => '/{{pluginKey}}',
|
||||
'icon' => 'plugin',
|
||||
'children' => [
|
||||
[
|
||||
'name' => '列表',
|
||||
'code' => '{{pluginKey}}:index',
|
||||
'app' => '{{pluginName}}',
|
||||
'path' => '/{{pluginKey}}/index',
|
||||
'component' => '/{{pluginKey}}/index/index',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 前端菜单配置
|
||||
*/
|
||||
|
||||
return [
|
||||
// 前端菜单配置
|
||||
];
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Web 菜单配置
|
||||
*/
|
||||
|
||||
return [
|
||||
// Web 菜单配置
|
||||
];
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
* {{pluginName}} 插件路由配置
|
||||
* 使用 Swagger 注解自动生成路由
|
||||
*/
|
||||
|
||||
use Webman\Route;
|
||||
use WebmanTech\Swagger\Swagger;
|
||||
use OpenApi\Annotations as OA;
|
||||
|
||||
/**
|
||||
* 注册 API 路由
|
||||
*/
|
||||
Route::group('/api', function () {
|
||||
Swagger::create()->registerRoute([
|
||||
'route_prefix' => '/{{pluginKey}}/openapi',
|
||||
'register_route' => true,
|
||||
'openapi_doc' => [
|
||||
'scan_path' => [
|
||||
base_path('plugin/{{pluginName}}/app/api'),
|
||||
],
|
||||
'modify' => function (OA\OpenApi $openapi) {
|
||||
$openapi->info->title = '{{pluginTitle}} API';
|
||||
$openapi->info->version = '1.0.0';
|
||||
$openapi->servers = [
|
||||
new OA\Server(
|
||||
[
|
||||
'url' => '/api',
|
||||
'description' => request()->host(),
|
||||
]
|
||||
),
|
||||
];
|
||||
/** @phpstan-ignore-next-line */
|
||||
if (!$openapi->components instanceof OA\Components) {
|
||||
$openapi->components = new OA\Components([]);
|
||||
}
|
||||
$openapi->components->securitySchemes = [
|
||||
new OA\SecurityScheme([
|
||||
'securityScheme' => 'api_key',
|
||||
'type' => 'apiKey',
|
||||
'name' => config('core.jwt.app.token_name', 'Authorization'),
|
||||
'in' => 'header',
|
||||
]),
|
||||
];
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
/**
|
||||
* 注册 AdminAPI 路由
|
||||
*/
|
||||
Route::group('/adminapi', function () {
|
||||
Swagger::create()->registerRoute([
|
||||
'route_prefix' => '/{{pluginKey}}/openapi',
|
||||
'register_route' => true,
|
||||
'openapi_doc' => [
|
||||
'scan_path' => [
|
||||
base_path('plugin/{{pluginName}}/app/adminapi'),
|
||||
],
|
||||
'modify' => function (OA\OpenApi $openapi) {
|
||||
$openapi->info->title = '{{pluginTitle}} API';
|
||||
$openapi->info->version = '1.0.0';
|
||||
$openapi->servers = [
|
||||
new OA\Server(
|
||||
[
|
||||
'url' => '/adminapi',
|
||||
'description' => request()->host(),
|
||||
]
|
||||
),
|
||||
];
|
||||
/** @phpstan-ignore-next-line */
|
||||
if (!$openapi->components instanceof OA\Components) {
|
||||
$openapi->components = new OA\Components([]);
|
||||
}
|
||||
$openapi->components->securitySchemes = [
|
||||
new OA\SecurityScheme([
|
||||
'securityScheme' => 'api_key',
|
||||
'type' => 'apiKey',
|
||||
'name' => config('core.jwt.app.token_name', 'Authorization'),
|
||||
'in' => 'header',
|
||||
]),
|
||||
];
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'locale' => config('app.lang'),
|
||||
'fallback_locale' => ['zh_CN', 'en'],
|
||||
'path' => base_path() . '/plugin/{{pluginName}}/resource/translations',
|
||||
];
|
||||
Reference in New Issue
Block a user