<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;

/**
 * 应用脚手架
 * 一键生成应用、业务模块、扩展插件的完整目录和骨架代码
 *
 * php think make:app crm
 * php think make:module mall notice
 * php think make:plugin mall points
 *
 * Class Make
 * @package app\command
 */
class Make extends Command
{
    private const ROOT = '';

    private string $rootPath = '';
    private string $action = '';
    private string $code = '';
    private string $appCode = '';
    private string $className = '';

    private string $apiBase = '';
    private string $adminBase = '';
    private string $apiAppBase = '';
    private string $adminSrc = '';

    /** @var string[] */
    private array $created = [];

    protected function configure(): void
    {
        $this->setName('make')
            ->addArgument('action', Argument::OPTIONAL, '操作类型: app | module | plugin')
            ->addArgument('arg1', Argument::OPTIONAL, '应用编码 (app) 或 模块/插件编码 (module/plugin)')
            ->addArgument('arg2', Argument::OPTIONAL, '模块/插件编码 (仅 module 和 plugin 操作需要)')
            ->setDescription('应用脚手架：生成应用、模块、插件的完整骨架');
    }


    protected function execute(Input $input, Output $output): void
    {
        if (!class_exists('think\\helper\\Str')) {
            $output->writeln('<error>缺少 topthink/think-helper 依赖</error>');
            return;
        }

        $this->rootPath = dirname($this->app->getRootPath()) . '/';

        $this->apiBase = $this->rootPath . 'api/';
        $this->apiAppBase = $this->apiBase . 'app/';
        $this->adminSrc = $this->rootPath . 'admin/src/';

        $operation = trim((string)$input->getArgument('action'));
        $arg1 = trim((string)$input->getArgument('arg1'));
        $arg2 = trim((string)$input->getArgument('arg2'));

        if (!in_array($operation, ['app', 'module', 'plugin'], true)) {
            $this->showHelp($output);
            return;
        }

        $this->action = $operation;

        if ($this->action === 'app') {
            $code = $arg1;
            if (empty($code) || !preg_match('/^[a-z][a-z0-9_]*$/', $code)) {
                $output->writeln('<error>编码必须是小写字母、数字和下划线，且以字母开头</error>');
                return;
            }
            $this->code = $code;
            $this->appCode = $code;
        } else {
            $this->code = $arg2;
            $this->appCode = $arg1;
            if (empty($this->code) || !preg_match('/^[a-z][a-z0-9_]*$/', $this->code)) {
                $output->writeln('<error>模块/插件编码必须是小写字母、数字和下划线，且以字母开头</error>');
                return;
            }
            if (empty($this->appCode) || !preg_match('/^[a-z][a-z0-9_]*$/', $this->appCode)) {
                $output->writeln('<error>应用编码必须是小写字母、数字和下划线，且以字母开头</error>');
                return;
            }
            if (!is_dir($this->apiBase . 'applications/' . $this->appCode)) {
                $output->writeln(sprintf('<error>应用 "%s" 不存在，请先执行 php think make app %s</error>', $this->appCode, $this->appCode));
                return;
            }
        }

        $this->className = $this->codeToClass($this->code);

        $this->created = [];

        try {
            $this->{'handle' . ucfirst($this->action)}();
        } catch (\Throwable $e) {
            $output->writeln('<error>' . $e->getMessage() . '</error>');
            return;
        }

        $output->writeln(sprintf('<info>✅ %s "%s" 骨架已生成</info>', $this->label(), $this->code));
        $output->writeln('');
        foreach ($this->created as $file) {
            $output->writeln('  <comment>+</comment> ' . $file);
        }
        $output->writeln('');
        $this->showNextSteps($output);
    }

    // ----------------------------------------------------------------
    // Stub rendering — templates live in stubs/ directory
    // ----------------------------------------------------------------

    private string $stubDir = '';

    private function initStubDir(): void
    {
        $this->stubDir = __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR;
    }

    /**
     * Render a stub file with {{placeholder}} substitution.
     * Placeholders: {{code}}, {{Code}}, {{class}}, {{Class}}, {{ind}}, {{Ind}}
     */
    private function renderStub(string $path, array $vars): string
    {
        if ($this->stubDir === '') { $this->initStubDir(); }
        $tpl = file_get_contents($this->stubDir . $path);
        if ($tpl === false) {
            throw new \RuntimeException("Stub not found: {$path}");
        }
        $keys = array_map(fn($k) => '{{' . $k . '}}', array_keys($vars));
        return str_replace($keys, array_values($vars), $tpl);
    }

    // ----------------------------------------------------------------
    // 应用
    // ----------------------------------------------------------------

    private function handleApplication(): void
    {
        $ind = $this->appCode;
        $apis = $this->apiBase . 'applications/' . $ind . '/';
        $adm = $this->adminSrc . 'applications/' . $ind . '/';
        $admRouter = $adm . 'router/';

        $label = $ind;

        // === 后端 ===
        $this->json($apis . 'manifest.json', [
            'code' => $ind, 'name' => $label, 'type' => 'application', 'version' => '1.0.0',
            'description' => $label . ' 应用', 'dependencies' => ['core'], 'modules' => [], 'plugins' => [],
            'route_bridges' => [
                'admin' => 'applications/' . $ind . '/route/admin.php',
                'app' => 'applications/' . $ind . '/route/app.php',
            ],
        ]);
        $this->json($apis . 'menus.json', []);
        $this->json($apis . 'permissions.json', []);
        $this->json($apis . 'settings.json', []);
        $this->json($apis . 'messages.json', []);

        $this->file($apis . 'route/admin.php', $this->applicationRouteBridgeContent($ind, 'admin'));
        $this->file($apis . 'route/app.php', $this->applicationRouteBridgeContent($ind, 'app'));
        $this->file($apis . 'event.php', $this->emptyEventContent());
        $this->file($apis . 'queue.php', $this->emptyQueueContent());

        // === 前端 ===
        $this->file($admRouter . 'settings.ts', $this->applicationSettingsRouteContent($ind));
        $this->file($admRouter . 'stats.ts', $this->applicationStatsRouteContent($ind));
        $this->file($adm . 'pages/settings/index.vue', $this->applicationSettingsPageContent($ind));
        $this->file($adm . 'pages/stats/index.vue', $this->applicationStatsPageContent($ind));
        $this->file($adm . 'api/settings.ts', $this->applicationSettingsApiContent());
        $this->file($adm . 'api/stats.ts', $this->applicationStatsApiContent());

        // === 数据 ===
        $sqlFile = $this->rootPath . 'api/applications/' . $ind . '/data/schema.sql';
        if (!is_file($sqlFile)) {
            $this->file($sqlFile, '-- ' . $label . ' 应用安装 SQL' . "\n" . '-- 请在此添加建表语句' . "\n");
        }
    }

    // ----------------------------------------------------------------
    // 业务模块
    // ----------------------------------------------------------------

    private function handleModule(): void
    {
        $ind = $this->appCode;
        $code = $this->code;
        $cls = $this->className;

        $mRoot = $this->apiBase . 'applications/' . $ind . '/modules/' . $code . '/';

        // === 后端：控制器（应用级目录） ===
        $ctrlDir = $this->apiBase . 'applications/' . $ind . '/adminapi/controller/' . $code . '/';
        $this->file($ctrlDir . $cls . '.php', $this->moduleControllerContent($ind, $code, $cls));

        // === 后端：模块核心文件 ===
        $this->json($mRoot . 'manifest.json', [
            'code' => $ind . '.' . $code,
            'name' => $cls,
            'type' => 'module',
            'version' => '1.0.0',
            'description' => $cls . ' 业务模块',
            'dependencies' => ['core', $ind],
            'permissions' => [$code . '.view', $code . '.save', $code . '.delete'],
            'route_bridges' => [
                'admin' => 'applications/' . $ind . '/modules/' . $code . '/route/admin.php',
                'app' => 'applications/' . $ind . '/modules/' . $code . '/route/app.php',
            ],
        ]);
        $this->file($mRoot . 'route/admin.php', $this->moduleRouteContent($ind, $code, $cls));
        $this->file($mRoot . 'route/app.php', "<?php\n// {$ind}/{$code} 前台路由\n");
        $this->file($mRoot . 'event.php', $this->emptyEventContent());
        $this->file($mRoot . 'queue.php', $this->emptyQueueContent());
        $this->file($mRoot . 'service/admin/' . $cls . 'Service.php', $this->applicationServiceContent($ind, $code, $cls));
        $this->file($mRoot . 'core/Core' . $cls . 'Service.php', $this->coreServiceContent($ind, $code, $cls));
        $this->file($mRoot . 'repository/' . $cls . 'Repository.php', $this->repositoryContent($ind, $code, $cls));
        $this->file($mRoot . 'model/' . $cls . '.php', $this->modelContent($ind, $code, $cls));
        $this->file($mRoot . 'validate/admin/' . $cls . 'Validator.php', $this->validatorContent($ind, $code, $cls));
        $this->file($mRoot . 'validate/domain/' . $cls . 'DomainValidator.php', $this->domainValidatorContent($ind, $code, $cls));

        // === 前端 ===
        $this->file($this->adminSrc . 'applications/' . $ind . '/pages/' . $code . '/index.vue', $this->modulePageContent($ind, $code, $cls));
        $this->file($this->adminSrc . 'applications/' . $ind . '/api/' . $code . '.ts', $this->moduleApiContent($ind, $code, $cls));
        $this->file($this->adminSrc . 'applications/' . $ind . '/router/' . $code . '.ts', $this->moduleRouteContentTs($ind, $code, $cls));

        // === 应用 manifest 追加 modules ===
        $this->appendapplicationManifestModule($ind, $code);
    }

    // ----------------------------------------------------------------
    // 扩展插件
    // ----------------------------------------------------------------

    private function handlePlugin(): void
    {
        $ind = $this->appCode;
        $code = $this->code;
        $cls = $this->className;

        $pRoot = $this->apiBase . 'applications/' . $ind . '/plugins/' . $code . '/';

        // === 后端 ===
        $this->file($pRoot . 'adminapi/controller/' . $cls . '.php', $this->pluginControllerContent($ind, $code, $cls));
        $this->json($pRoot . 'manifest.json', [
            'code' => $ind . '.' . $code,
            'name' => $cls,
            'type' => 'plugin',
            'version' => '1.0.0',
            'description' => $cls . ' 扩展插件',
            'dependencies' => ['core', $ind],
            'permissions' => ['plugins.' . $code . '.view', 'plugins.' . $code . '.save', 'plugins.' . $code . '.delete'],
            'route_bridges' => [
                'admin' => 'applications/' . $ind . '/plugins/' . $code . '/route/admin.php',
                'app' => 'applications/' . $ind . '/plugins/' . $code . '/route/app.php',
            ],
            'extension_points' => [],
            'plugins_meta' => [
                'type' => 'other',
                'description' => $cls . ' 插件能力。',
                'icon' => 'iconfont iconplugin',
                'sort' => 99,
            ],
        ]);
        $this->file($pRoot . 'route/admin.php', $this->pluginRouteContent($ind, $code, $cls));
        $this->file($pRoot . 'route/app.php', "<?php\n// {$ind}/{$code} 前台路由\n");
        $this->file($pRoot . 'event.php', $this->emptyEventContent());
        $this->file($pRoot . 'queue.php', $this->emptyQueueContent());
        $this->file($pRoot . 'service/admin/' . $cls . 'Service.php', $this->applicationServiceContent($ind, $code, $cls, 'plugin'));
        $this->file($pRoot . 'core/Core' . $cls . 'Service.php', $this->coreServiceContent($ind, $code, $cls, 'plugin'));
        $this->file($pRoot . 'repository/' . $cls . 'Repository.php', $this->repositoryContent($ind, $code, $cls, 'plugin'));
        $this->file($pRoot . 'model/' . $cls . '.php', $this->modelContent($ind, $code, $cls, 'plugin'));
        $this->file($pRoot . 'validate/admin/' . $cls . 'Validator.php', $this->validatorContent($ind, $code, $cls, 'plugin'));
        $this->file($pRoot . 'validate/domain/' . $cls . 'DomainValidator.php', $this->domainValidatorContent($ind, $code, $cls, 'plugin'));
        $this->file($pRoot . 'extension/.gitkeep', '');
        $this->file($pRoot . 'queue/.gitkeep', '');

        // === 前端 ===
        $pluginRoot = $this->adminSrc . 'applications/' . $ind . '/plugins/';
        $this->file($pluginRoot . $code . '/pages/index.vue', $this->pluginPageContent($ind, $code, $cls));
        $this->file($pluginRoot . $code . '/api/index.ts', $this->pluginApiContent($ind, $code, $cls));
        $this->file($pluginRoot . $code . '/router.ts', $this->pluginRouteContentTs($ind, $code, $cls));
        $this->ensurePluginRouterAggregator($ind);

        // === 应用 manifest 追加 plugins ===
        $this->appendapplicationManifestPlugin($ind, $code);
    }

    // ----------------------------------------------------------------
    // 文件写入
    // ----------------------------------------------------------------

    private function file(string $path, string $content): void
    {
        $dir = dirname($path);
        if (!is_dir($dir)) {
            mkdir($dir, 0755, true);
        }
        file_put_contents($path, $content);
        $this->created[] = str_replace([$this->rootPath, '\\'], ['', '/'], $path);
    }

    private function json(string $path, array $data): void
    {
        $this->file($path, json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n");
    }

    // ----------------------------------------------------------------
    // 内容模板 — 应用
    // ----------------------------------------------------------------

    private function applicationRouteBridgeContent(string $ind, string $side): string
    {
        $vert = $side === 'admin' ? '\\AdminAuth::class' : '\\Auth::class';
        return $this->renderStub('industry/route-bridge.php.stub', [
            'side' => $side,
        ]);
    }

    private function applicationSettingsRouteContent(string $ind): string
    {
        return sprintf(
            'import type { RouteRecordRaw } from \'vue-router\';
import Layout from \'@/layouts/index.vue\';

export default [
  {
    path: \'/%s/settings\',
    name: \'%sSettings\',
    component: Layout,
    meta: { hiddenBreadcrumb: true, icon: \'iconfont iconshezhi1\', orderNo: 50, permission: \'system.view\' },
    children: [
      {
        path: \'\',
        name: \'%sSettingsPage\',
        component: () => import(\'@/applications/%s/pages/settings/index.vue\'),
        meta: { title: { zh_CN: \'应用设置\', en_US: \'%s Settings\' }, permission: \'system.view\' },
      },
    ],
  },
] satisfies RouteRecordRaw[];
',
            $ind, ucfirst($ind), ucfirst($ind), $ind, ucfirst($ind)
        );
    }

    private function applicationStatsRouteContent(string $ind): string
    {
        return sprintf(
            'import type { RouteRecordRaw } from \'vue-router\';
import Layout from \'@/layouts/index.vue\';

export default [
  {
    path: \'/%s/stats\',
    name: \'%sStats\',
    component: Layout,
    meta: { hiddenBreadcrumb: true, icon: \'iconfont iconshujutongji\', orderNo: 20, permission: \'system.view\' },
    children: [
      {
        path: \'\',
        name: \'%sStatsPage\',
        component: () => import(\'@/applications/%s/pages/stats/index.vue\'),
        meta: { title: { zh_CN: \'应用概况\', en_US: \'%s Overview\' }, permission: \'system.view\' },
      },
    ],
  },
] satisfies RouteRecordRaw[];
',
            $ind, ucfirst($ind), ucfirst($ind), $ind, ucfirst($ind)
        );
    }

    private function applicationSettingsPageContent(string $ind): string
    {
        return sprintf(
            '<template>
  <t-card :bordered="false" title="应用设置">
    <t-alert
      theme="info"
      message="脚手架已生成设置页骨架，请继续补充配置项与 /%s/settings/get、/%s/settings/save 接口。"
      class="page-alert"
    />

    <t-tabs v-model="activeTab">
      <t-tab-panel value="basic" label="基础配置">
        <t-form :data="formData" label-width="120px" class="form">
          <t-form-item label="应用名称">
            <t-input v-model="formData.name" placeholder="请输入应用名称" />
          </t-form-item>
          <t-form-item label="应用描述">
            <t-textarea v-model="formData.description" :autosize="{ minRows: 3, maxRows: 5 }" placeholder="请输入应用描述" />
          </t-form-item>
        </t-form>
      </t-tab-panel>
    </t-tabs>

    <div class="footer-actions">
      <t-button theme="primary" @click="handleSave">保存</t-button>

  </t-card>
</template>

<script setup lang="ts">
import { reactive, ref } from \'vue\';
import { MessagePlugin } from \'tdesign-vue-next\';

const activeTab = ref(\'basic\');
const formData = reactive({
  name: \'%s 应用\',
  description: \'请按业务需要继续补充设置项与保存逻辑\',
});

const handleSave = async () => {
  MessagePlugin.info(\'请继续实现设置保存逻辑\');
};
</script>

<style scoped>
.page-alert {
  margin-bottom: 16px;
}

.form {
  max-width: 720px;
  padding-top: 8px;
}

.footer-actions {
  margin-top: 24px;
  padding-top: 16px;
  border-top: 1px solid var(--td-component-border);
}
</style>
',
            $ind, $ind, $ind
        );
    }

    private function applicationStatsPageContent(string $ind): string
    {
        return sprintf(
            '<template>
  <t-card :bordered="false" title="应用概况">
    <t-alert
      theme="info"
      message="脚手架已生成统计页骨架，请继续接入 /%s/stats/overview 接口与应用 KPI。"
      class="page-alert"
    />
    <t-row :gutter="16" class="kpi-row">
      <t-col :span="6">
        <t-card class="kpi-card">
          <div class="kpi-value">--
          <div class="kpi-label">今日订单
        </t-card>
      </t-col>
      <t-col :span="6">
        <t-card class="kpi-card">
          <div class="kpi-value">--
          <div class="kpi-label">今日营收
        </t-card>
      </t-col>
      <t-col :span="6">
        <t-card class="kpi-card">
          <div class="kpi-value">--
          <div class="kpi-label">新增用户
        </t-card>
      </t-col>
      <t-col :span="6">
        <t-card class="kpi-card">
          <div class="kpi-value">--
          <div class="kpi-label">待处理
        </t-card>
      </t-col>
    </t-row>
  </t-card>
</template>

<style scoped lang="less">
.page-alert {
  margin-bottom: 16px;
}

.kpi-row { margin-bottom: 16px; }
.kpi-card { text-align: center; }
.kpi-value { font-size: 28px; font-weight: 700; color: var(--td-brand-color); }
.kpi-label { font-size: 14px; color: var(--td-text-color-secondary); margin-top: 8px; }
</style>
',
            $ind
        );
    }

    private function applicationSettingsApiContent(): string
    {
        return sprintf(
            'import { request } from \'@/utils/request\';

export interface %sSettingsRow {
  key1?: string;
}

export function get%sSettings() {
  return request.get({ url: \'/%s/settings/get\' }, { isTransformResponse: false });
}

export function save%sSettings(data: Record<string, unknown>) {
  return request.post({ url: \'/%s/settings/save\', data }, { isTransformResponse: false });
}
',
            ucfirst($this->appCode), ucfirst($this->appCode), $this->appCode,
            ucfirst($this->appCode), $this->appCode
        );
    }

    private function applicationStatsApiContent(): string
    {
        return sprintf(
            'import { request } from \'@/utils/request\';

export interface %sStatsRow {
  orders?: number;
  revenue?: number;
  newUsers?: number;
}

export function get%sStats(params?: Record<string, unknown>) {
  return request.get({ url: \'/%s/stats/overview\', params }, { isTransformResponse: false });
}
',
            ucfirst($this->appCode), ucfirst($this->appCode), $this->appCode
        );
    }

    // ----------------------------------------------------------------
    // 内容模板 — 模块
    // ----------------------------------------------------------------

    private function moduleControllerContent(string $ind, string $code, string $cls): string
    {
        $nsCtrl = "Applications\\{$ind}\\adminapi\\controller\\{$code}";
        $nsSvc = "Applications\\{$ind}\\modules\\{$code}\\service\\admin\\{$cls}Service";
        $nsVal = "Applications\\{$ind}\\modules\\{$code}\\validate\\admin\\{$cls}Validator";
        $nsDVal = "Applications\\{$ind}\\modules\\{$code}\\validate\\domain\\{$cls}DomainValidator";

        return <<<PHP
<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
declare(strict_types=1);

namespace {$nsCtrl};

use {$nsSvc};
use {$nsVal};
use {$nsDVal};
use app\adminapi\controller\BaseAdminController;
use think\Request;

class {$cls} extends BaseAdminController
{
    public function list(Request \$request)
    {
        \$params = \$request->get();
        \$this->validate(\$params, {$cls}Validator::class . '.list');

        return json(\$this->app->make({$cls}Service::class)->list(\$request));
    }


    public function detail(\$id, Request \$request)
    {
        \$this->validate(['id' => \$id], {$cls}Validator::class . '.detail');

        return json(\$this->app->make({$cls}Service::class)->detail((int)\$id, \$request));
    }


    public function save(Request \$request)
    {
        \$params = \$request->post();
        \$this->validate(\$params, {$cls}Validator::class . '.save');
        \$this->validateDomain(\$this->app->make({$cls}DomainValidator::class), \$params, 'save');

        return json(\$this->app->make({$cls}Service::class)->save(\$request));
    }


    public function delete(Request \$request)
    {
        \$params = \$request->post();
        \$this->validate(\$params, {$cls}Validator::class . '.delete');
        \$this->validateDomain(\$this->app->make({$cls}DomainValidator::class), \$params, 'delete');

        return json(\$this->app->make({$cls}Service::class)->delete(\$request));
    }
}

PHP;
    }

    private function moduleRouteContent(string $ind, string $code, string $cls): string
    {
        return <<<PHP
<?php
// {$ind}/{$code} 业务模块后台路由

use think\facade\Route;

Route::get('{$ind}/{$code}/list', 'Applications\\{$ind}\\adminapi\\controller\\{$code}\\{$cls}@list')->middleware(\\app\\middleware\\AdminPermission::class, '{$code}.view');
Route::get('{$ind}/{$code}/detail/:id', 'Applications\\{$ind}\\adminapi\\controller\\{$code}\\{$cls}@detail')->middleware(\\app\\middleware\\AdminPermission::class, '{$code}.view');
Route::post('{$ind}/{$code}/save', 'Applications\\{$ind}\\adminapi\\controller\\{$code}\\{$cls}@save')->middleware(\\app\\middleware\\AdminPermission::class, '{$code}.save');
Route::post('{$ind}/{$code}/delete', 'Applications\\{$ind}\\adminapi\\controller\\{$code}\\{$cls}@delete')->middleware(\\app\\middleware\\AdminPermission::class, '{$code}.delete');

PHP;
    }

    private function applicationServiceContent(string $ind, string $code, string $cls, string $type = 'module'): string
    {
        $sub = $type === 'plugin' ? 'plugins' : 'modules';
        $ns = "Applications\\{$ind}\\{$sub}\\{$code}\\service\\admin";
        $cSvc = "Applications\\{$ind}\\{$sub}\\{$code}\\core\\Core{$cls}Service";

        return <<<PHP
<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
declare(strict_types=1);

namespace {$ns};

use {$cSvc};
use app\service\admin\BaseAdminService;
use think\Request;

class {$cls}Service extends BaseAdminService
{
    public function list(Request \$request): array
    {
        return ['code' => 0, 'data' => []];
    }


    public function detail(int \$id, Request \$request): array
    {
        return ['code' => 0, 'data' => []];
    }


    public function save(Request \$request): array
    {
        return \$this->core()->save(\$request->post());
    }


    public function delete(Request \$request): array
    {
        return \$this->core()->delete((int)\$request->post('id', 0));
    }

    private function core(): Core{$cls}Service
    {
        return \$this->app->make(Core{$cls}Service::class);
    }
}

PHP;
    }

    private function coreServiceContent(string $ind, string $code, string $cls, string $type = 'module'): string
    {
        $sub = $type === 'plugin' ? 'plugins' : 'modules';
        $ns = "Applications\\{$ind}\\{$sub}\\{$code}\\core";

        return <<<PHP
<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
declare(strict_types=1);

namespace {$ns};

use Core\service\BaseCoreService;

/**
 * Core
 * @package app\command
 */
class Core{$cls}Service extends BaseCoreService
{
}

PHP;
    }

    private function repositoryContent(string $ind, string $code, string $cls, string $type = 'module'): string
    {
        $sub = $type === 'plugin' ? 'plugins' : 'modules';
        $ns = "Applications\\{$ind}\\{$sub}\\{$code}\\repository";
        $nsModel = "Applications\\{$ind}\\{$sub}\\{$code}\\model";

        return <<<PHP
<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
declare(strict_types=1);

namespace {$ns};

use {$nsModel}\\{$cls};
use app\repository\BaseRepository;

class {$cls}Repository extends BaseRepository
{
    public function model(): string
    {
        return {$cls}::class;
    }
}

PHP;
    }

    private function modelContent(string $ind, string $code, string $cls, string $type = 'module'): string
    {
        $sub = $type === 'plugin' ? 'plugins' : 'modules';
        $ns = "Applications\\{$ind}\\{$sub}\\{$code}\\model";

        return <<<PHP
<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
declare(strict_types=1);

namespace {$ns};

use think\Model;

class {$cls} extends Model
{
    protected \$name = 'onezan_{$ind}_{$code}';
}

PHP;
    }

    private function validatorContent(string $ind, string $code, string $cls, string $type = 'module'): string
    {
        $sub = $type === 'plugin' ? 'plugins' : 'modules';
        $ns = "Applications\\{$ind}\\{$sub}\\{$code}\\validate\\admin";

        return <<<PHP
<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
declare(strict_types=1);

namespace {$ns};

use think\Validate;

class {$cls}Validator extends Validate
{
    protected \$rule = [
        'id'      => 'integer|gt:0',
        'keyword' => 'max:100',
        'page'    => 'integer|gt:0',
        'limit'   => 'integer|between:1,100',
    ];

    protected \$message = [
        'id.integer'   => 'ID必须为整数',
        'id.gt'        => 'ID必须大于0',
        'keyword.max'  => '关键词长度不能超过100',
        'page.integer' => '页码必须为整数',
        'page.gt'      => '页码必须大于0',
        'limit.integer' => '每页条数必须为整数',
        'limit.between' => '每页条数需在1-100之间',
    ];

    protected \$scene = [
        'list'   => ['keyword', 'page', 'limit'],
        'detail' => ['id'],
        'save'   => [],
        'delete' => ['id'],
    ];
}

PHP;
    }

    private function domainValidatorContent(string $ind, string $code, string $cls, string $type = 'module'): string
    {
        $sub = $type === 'plugin' ? 'plugins' : 'modules';
        $ns = "Applications\\{$ind}\\{$sub}\\{$code}\\validate\\domain";

        return <<<PHP
<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
declare(strict_types=1);

namespace {$ns};

use app\validate\domain\DomainValidatorInterface;

class {$cls}DomainValidator implements DomainValidatorInterface
{
    public function validate(array \$data, string \$scene = ''): array
    {
        \$errors = match (\$scene) {
            'save' => \$this->validateSave(\$data),
            'delete' => \$this->validateDelete(\$data),
            default => [],
        };

        return ['ok' => empty(\$errors), 'errors' => \$errors];
    }

    private function validateSave(array \$data): array
    {
        \$errors = [];
        return \$errors;
    }

    private function validateDelete(array \$data): array
    {
        \$errors = [];
        if (empty(\$data['id'] ?? 0)) {
            \$errors['id'] = 'ID_REQUIRED';
        }
        return \$errors;
    }
}

PHP;
    }

    // ----------------------------------------------------------------
    // 内容模板 — 插件（与模块相似，但控制器在插件目录下）
    // ----------------------------------------------------------------

    private function pluginControllerContent(string $ind, string $code, string $cls): string
    {
        $nsCtrl = "Applications\\{$ind}\\plugins\\{$code}\\adminapi\\controller";
        $nsSvc = "Applications\\{$ind}\\plugins\\{$code}\\service\\admin\\{$cls}Service";
        $nsVal = "Applications\\{$ind}\\plugins\\{$code}\\validate\\admin\\{$cls}Validator";
        $nsDVal = "Applications\\{$ind}\\plugins\\{$code}\\validate\\domain\\{$cls}DomainValidator";

        return <<<PHP
<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
declare(strict_types=1);

namespace {$nsCtrl};

use {$nsSvc};
use {$nsVal};
use {$nsDVal};
use app\adminapi\controller\BaseAdminController;
use think\Request;

class {$cls} extends BaseAdminController
{
    public function list(Request \$request)
    {
        \$params = \$request->get();
        \$this->validate(\$params, {$cls}Validator::class . '.list');

        return json(\$this->app->make({$cls}Service::class)->list(\$request));
    }


    public function detail(\$id, Request \$request)
    {
        \$this->validate(['id' => \$id], {$cls}Validator::class . '.detail');

        return json(\$this->app->make({$cls}Service::class)->detail((int)\$id, \$request));
    }


    public function save(Request \$request)
    {
        \$params = \$request->post();
        \$this->validate(\$params, {$cls}Validator::class . '.save');
        \$this->validateDomain(\$this->app->make({$cls}DomainValidator::class), \$params, 'save');

        return json(\$this->app->make({$cls}Service::class)->save(\$request));
    }


    public function delete(Request \$request)
    {
        \$params = \$request->post();
        \$this->validate(\$params, {$cls}Validator::class . '.delete');
        \$this->validateDomain(\$this->app->make({$cls}DomainValidator::class), \$params, 'delete');

        return json(\$this->app->make({$cls}Service::class)->delete(\$request));
    }
}

PHP;
    }

    private function pluginRouteContent(string $ind, string $code, string $cls): string
    {
        return <<<PHP
<?php
// {$ind} 扩展插件 {$code} 后台路由

use think\facade\Route;

Route::get('{$ind}/plugins/{$code}/list', 'Applications\\{$ind}\\plugins\\{$code}\\adminapi\\controller\\{$cls}@list')->middleware(\\app\\middleware\\AdminPermission::class, 'plugins.{$code}.view');
Route::get('{$ind}/plugins/{$code}/detail/:id', 'Applications\\{$ind}\\plugins\\{$code}\\adminapi\\controller\\{$cls}@detail')->middleware(\\app\\middleware\\AdminPermission::class, 'plugins.{$code}.view');
Route::post('{$ind}/plugins/{$code}/save', 'Applications\\{$ind}\\plugins\\{$code}\\adminapi\\controller\\{$cls}@save')->middleware(\\app\\middleware\\AdminPermission::class, 'plugins.{$code}.save');
Route::post('{$ind}/plugins/{$code}/delete', 'Applications\\{$ind}\\plugins\\{$code}\\adminapi\\controller\\{$cls}@delete')->middleware(\\app\\middleware\\AdminPermission::class, 'plugins.{$code}.delete');

PHP;
    }

    // ----------------------------------------------------------------
    // 前端模板
    // ----------------------------------------------------------------

    private function modulePageContent(string $ind, string $code, string $cls): string
    {
        $apiPath = "@/applications/{$ind}/api/{$code}";

        return <<<VUE
<template>
  <t-card :bordered="false">

      <t-form class="search-form" :data="searchForm" layout="inline" @submit="handleSearch">
        <t-form-item label="关键词" name="keyword">
          <t-input v-model="searchForm.keyword" placeholder="请输入关键词" />
        </t-form-item>
        <t-form-item>
          <t-button theme="primary" type="submit">

            查询
          </t-button>
          <t-button theme="default" variant="base" @click="handleReset">

            重置
          </t-button>
          <t-button class="search-action-btn" @click="handleAdd">

            新增
          </t-button>
        </t-form-item>
      </t-form>

      <t-table
        :data="tableData"
        :columns="tableColumns"
        row-key="id"
        :loading="dataLoading"
        :pagination="pagination"
        hover
        @page-change="handlePageChange"
      >
        <template #status="{ row }">
          <t-tag :theme="row.status === 1 ? 'success' : 'danger'" variant="light">
            {{ row.status === 1 ? '启用' : '禁用' }}
          </t-tag>
        </template>
        <template #op="{ row }">
          <t-link theme="primary" hover="color" @click="handleEdit(row)">

            编辑
          </t-link>
          <t-popconfirm content="确认删除吗？" @confirm="handleDelete(row)">
            <t-link theme="danger" hover="color" class="op-link">

              删除
            </t-link>
          </t-popconfirm>
        </template>
      </t-table>

  </t-card>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';
import { MessagePlugin, type PrimaryTableCol, type TableRowData } from 'tdesign-vue-next';


import { get{$cls}List, delete{$cls}, type {$cls}Row } from '{$apiPath}';
import { usePermission } from '@/hooks/use-permission';
import type { ApiResponse, ListResponse, PageInfo } from '@/types/common';

const searchForm = reactive({
  keyword: '',
});

const tableData = ref<{$cls}Row[]>([]);
const dataLoading = ref(false);

const pagination = reactive({
  current: 1,
  pageSize: 10,
  total: 0,
});

const columns: PrimaryTableCol<{$cls}Row>[] = [
  { colKey: 'id', title: 'ID', width: 80 },
  { colKey: 'name', title: '名称' },
  { colKey: 'status', title: '状态', width: 100, cell: 'status' },
  { colKey: 'op', title: '操作', width: 150, fixed: 'right' as const, cell: 'op' },
];

const tableColumns = columns as unknown as PrimaryTableCol<TableRowData>[];

const fetchList = async () => {
  dataLoading.value = true;
  try {
    const res = (await get{$cls}List({
      ...searchForm,
      page: pagination.current,
      limit: pagination.pageSize,
    })) as ListResponse<{$cls}Row>;
    if (res.code === 0) {
      tableData.value = res.data?.data ?? [];
      pagination.total = Number(res.data?.total ?? 0);
      return;
    }
    MessagePlugin.error(res.msg || '获取列表失败');
  } catch (_error) {
    MessagePlugin.error('获取列表失败');
  } finally {
    dataLoading.value = false;
  }
};

const handleSearch = () => {
  pagination.current = 1;
  fetchList();
};

const handleReset = () => {
  searchForm.keyword = '';
  handleSearch();
};

const handlePageChange = (pageInfo: PageInfo) => {
  pagination.current = pageInfo.current;
  pagination.pageSize = pageInfo.pageSize;
  fetchList();
};

const handleAdd = () => {
  MessagePlugin.info('新增功能待实现');
};

const handleEdit = (_row: {$cls}Row) => {
  MessagePlugin.info('编辑功能待实现');
};

const handleDelete = async (row: {$cls}Row) => {
  try {
    const res = (await delete{$cls}(Number(row.id))) as ApiResponse;
    if (res.code === 0) {
      MessagePlugin.success('删除成功');
      fetchList();
      return;
    }
    MessagePlugin.error(res.msg || '删除失败');
  } catch (_error) {
    MessagePlugin.error('删除失败');
  }
};

onMounted(() => {
  fetchList();
});
</script>

<style scoped lang="less">
.table-container {
}
</style>
VUE;
    }

    private function moduleApiContent(string $ind, string $code, string $cls): string
    {
        return <<<TS
import { request } from '@/utils/request';
import type { ApiResponse, ItemResponse, ListResponse } from '@/types/common';

export type {$cls}Row = {
  id?: number;
  name: string;
  status: number;
  create_time?: string;
  update_time?: string;
};

export function get{$cls}List(params: Record<string, unknown>) {
  return request.get(
    { url: '/{$ind}/{$code}/list', params },
    { isTransformResponse: false },
  ) as Promise<ListResponse<{$cls}Row>>;
}

export function get{$cls}Detail(id: number) {
  return request.get(
    { url: '/{$ind}/{$code}/detail/' + id },
    { isTransformResponse: false },
  ) as Promise<ItemResponse<{$cls}Row>>;
}

export function save{$cls}(data: Record<string, unknown>) {
  return request.post(
    { url: '/{$ind}/{$code}/save', data },
    { isTransformResponse: false },
  ) as Promise<ApiResponse<{$cls}Row>>;
}

export function delete{$cls}(id: number) {
  return request.post(
    { url: '/{$ind}/{$code}/delete', data: { id } },
    { isTransformResponse: false },
  ) as Promise<ApiResponse>;
}
TS;
    }

    private function moduleRouteContentTs(string $ind, string $code, string $cls): string
    {
        return <<<TS
import type { RouteRecordRaw } from 'vue-router';
import Layout from '@/layouts/index.vue';

export default [
  {
    path: '/{$ind}/{$code}',
    name: '{$ind}{$cls}',
    component: Layout,
    redirect: '/{$ind}/{$code}/index',
    meta: {
      title: { zh_CN: '{$cls}', en_US: '{$cls}' },
      menuTitle: { zh_CN: '{$cls}', en_US: '{$cls}' },
      icon: 'iconfont iconchanpin',
      orderNo: 10,
      permission: '{$code}.view',
    },
    children: [
      {
        path: 'index',
        name: '{$ind}{$cls}Index',
        component: () => import('@/applications/{$ind}/pages/{$code}/index.vue'),
        meta: {
          title: { zh_CN: '{$cls}列表', en_US: '{$cls} List' },
          permission: '{$code}.view',
        },
      },
    ],
  },
] satisfies RouteRecordRaw[];
TS;
    }

    private function pluginPageContent(string $ind, string $code, string $cls): string
    {
        $apiPath = "@/applications/{$ind}/plugins/{$code}/api";

        return <<<VUE
<template>
  <t-card :bordered="false">

      <t-form class="search-form" :data="searchForm" layout="inline" @submit="handleSearch">
        <t-form-item label="关键词" name="keyword">
          <t-input v-model="searchForm.keyword" placeholder="请输入关键词" />
        </t-form-item>
        <t-form-item>
          <t-button theme="primary" type="submit">

            查询
          </t-button>
          <t-button theme="default" variant="base" @click="handleReset">

            重置
          </t-button>
        </t-form-item>
      </t-form>

      <t-table
        :data="tableData"
        :columns="tableColumns"
        row-key="id"
        :loading="dataLoading"
        :pagination="pagination"
        hover
        @page-change="handlePageChange"
      >
        <template #op="{ row }">
          <t-link theme="primary" hover="color" @click="handleEdit(row)">

            编辑
          </t-link>
        </template>
      </t-table>

  </t-card>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';
import { MessagePlugin, type PrimaryTableCol, type TableRowData } from 'tdesign-vue-next';

import { get{$cls}List, type {$cls}Row } from '{$apiPath}';
import type { ListResponse, PageInfo } from '@/types/common';

const searchForm = reactive({ keyword: '' });
const tableData = ref<{$cls}Row[]>([]);
const dataLoading = ref(false);
const pagination = reactive({ current: 1, pageSize: 10, total: 0 });

const columns: PrimaryTableCol<{$cls}Row>[] = [
  { colKey: 'id', title: 'ID', width: 80 },
  { colKey: 'name', title: '名称' },
  { colKey: 'op', title: '操作', width: 120, cell: 'op' },
];

const tableColumns = columns as unknown as PrimaryTableCol<TableRowData>[];

const fetchList = async () => {
  dataLoading.value = true;
  try {
    const res = (await get{$cls}List({
      ...searchForm,
      page: pagination.current,
      limit: pagination.pageSize,
    })) as ListResponse<{$cls}Row>;
    if (res.code === 0) {
      tableData.value = res.data?.data ?? [];
      pagination.total = Number(res.data?.total ?? 0);
      return;
    }
    MessagePlugin.error(res.msg || '获取列表失败');
  } catch (_error) {
    MessagePlugin.error('获取列表失败');
  } finally {
    dataLoading.value = false;
  }
};

const handleSearch = () => { pagination.current = 1; fetchList(); };
const handleReset = () => { searchForm.keyword = ''; handleSearch(); };
const handlePageChange = (pageInfo: PageInfo) => { pagination.current = pageInfo.current; pagination.pageSize = pageInfo.pageSize; fetchList(); };
const handleEdit = (_row: {$cls}Row) => {
  MessagePlugin.info('请继续实现插件编辑逻辑');
};

onMounted(() => { fetchList(); });
</script>
VUE;
    }

    private function pluginApiContent(string $ind, string $code, string $cls): string
    {
        return <<<TS
import { request } from '@/utils/request';
import type { ApiResponse, ItemResponse, ListResponse } from '@/types/common';

export type {$cls}Row = {
  id?: number;
  name: string;
  status: number;
  create_time?: string;
  update_time?: string;
};

export function get{$cls}List(params: Record<string, unknown>) {
  return request.get(
    { url: '/{$ind}/plugins/{$code}/list', params },
    { isTransformResponse: false },
  ) as Promise<ListResponse<{$cls}Row>>;
}

export function get{$cls}Detail(id: number) {
  return request.get(
    { url: '/{$ind}/plugins/{$code}/detail/' + id },
    { isTransformResponse: false },
  ) as Promise<ItemResponse<{$cls}Row>>;
}

export function save{$cls}(data: Record<string, unknown>) {
  return request.post(
    { url: '/{$ind}/plugins/{$code}/save', data },
    { isTransformResponse: false },
  ) as Promise<ApiResponse<{$cls}Row>>;
}

export function delete{$cls}(id: number) {
  return request.post(
    { url: '/{$ind}/plugins/{$code}/delete', data: { id } },
    { isTransformResponse: false },
  ) as Promise<ApiResponse>;
}
TS;
    }

    private function pluginRouteContentTs(string $ind, string $code, string $cls): string
    {
        return <<<TS
import type { RouteRecordRaw } from 'vue-router';

export default {
  path: '{$code}',
  name: '{$ind}{$cls}Plugin',
  component: () => import('@/applications/{$ind}/plugins/{$code}/pages/index.vue'),
  meta: { title: { zh_CN: '{$cls}', en_US: '{$cls}' }, permission: 'plugins.{$code}.view' },
} satisfies RouteRecordRaw;
TS;
    }

    private function pluginRouterAggregatorContent(string $ind): string
    {
        return <<<TS
import type { RouteRecordRaw } from 'vue-router';

import Layout from '@/layouts/index.vue';

const pluginModules = import.meta.glob<{ default: RouteRecordRaw }>('./*/router.ts', { eager: true });
const pluginChildren = Object.values(pluginModules).map((m) => m.default);
const defaultPath = pluginChildren[0]?.path ? '/{$ind}/plugins/' + pluginChildren[0].path : '/{$ind}/stats';

export default [
  {
    path: '/{$ind}/plugins',
    name: '{$ind}Plugins',
    component: Layout,
    redirect: defaultPath,
    meta: {
      title: { zh_CN: '应用插件', en_US: 'Application Plugins' },
      icon: 'iconfont iconyingyong21',
      orderNo: 30,
      permission: 'plugins.view',
    },
    children: [...pluginChildren],
  },
] satisfies RouteRecordRaw[];
TS;
    }

    // ----------------------------------------------------------------
    // 辅助方法
    // ----------------------------------------------------------------

    private function codeToClass(string $code): string
    {
        return str_replace('_', '', ucwords($code, '_'));
    }

    private function ensurePluginRouterAggregator(string $ind): void
    {
        $routerFile = $this->adminSrc . 'applications/' . $ind . '/plugins/router.ts';
        if (!is_file($routerFile)) {
            $this->file($routerFile, $this->pluginRouterAggregatorContent($ind));
        }
    }

    private function emptyEventContent(): string
    {
        return <<<PHP
<?php
declare(strict_types=1);

return [];
PHP;
    }

    private function emptyQueueContent(): string
    {
        return <<<PHP
<?php
declare(strict_types=1);

return [];
PHP;
    }

    private function appendapplicationManifestModule(string $ind, string $code): void
    {
        $file = $this->apiBase . 'applications/' . $ind . '/manifest.json';
        if (!is_file($file)) return;
        $manifest = json_decode(file_get_contents($file), true) ?: [];
        if (!isset($manifest['modules'])) $manifest['modules'] = [];
        if (!in_array($code, $manifest['modules'], true)) {
            $manifest['modules'][] = $code;
            file_put_contents($file, json_encode($manifest, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n");
        }
    }

    private function appendapplicationManifestPlugin(string $ind, string $code): void
    {
        $file = $this->apiBase . 'applications/' . $ind . '/manifest.json';
        if (!is_file($file)) return;
        $manifest = json_decode(file_get_contents($file), true) ?: [];
        if (!isset($manifest['plugins'])) $manifest['plugins'] = [];
        if (!in_array($code, $manifest['plugins'], true)) {
            $manifest['plugins'][] = $code;
            file_put_contents($file, json_encode($manifest, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n");
        }
    }

    // ----------------------------------------------------------------
    // 输出
    // ----------------------------------------------------------------

    private function label(): string
    {
        return ['app' => '应用', 'module' => '业务模块', 'plugin' => '扩展插件'][$this->action] ?? '';
    }

    private function showNextSteps(Output $output): void
    {
        $output->writeln('下一步：');

        if ($this->action === 'app') {
            $output->writeln('  1. 编辑 api/applications/' . $this->code . '/menus.json 配置菜单');
            $output->writeln('  2. 编辑 api/applications/' . $this->code . '/permissions.json 配置权限');
            $output->writeln('  3. 编辑 api/applications/' . $this->code . '/settings.json 配置设置项');
            $output->writeln('  4. 按需补充 admin/src/applications/' . $this->code . '/router 与 pages 下的页面实现');
            $output->writeln('  5. php think make module ' . $this->code . ' {模块}  创建业务模块');
            $output->writeln('  6. php think make plugin ' . $this->code . ' {插件}  创建扩展插件');
            $output->writeln('  7. 视需要补充 event.php / queue.php 声明式生命周期定义');
            $output->writeln('  8. 创建 api/applications/' . $this->code . '/data/schema.sql 建表');
            $output->writeln('  9. php think app install ' . $this->code . '  安装应用');
        } elseif ($this->action === 'module') {
            $output->writeln('  1. 编辑应用层 Service（api/applications/' . $this->appCode . '/modules/' . $this->code . '/service/admin/' . $this->className . 'Service.php）');
            $output->writeln('  2. 编辑 Core 层 Service 实现事务和状态流转');
            $output->writeln('  3. 编辑 Validator 补充校验规则');
            $output->writeln('  4. 编辑 DomainValidator 补充领域校验');
            $output->writeln('  5. 编辑 admin/src/applications/' . $this->appCode . '/pages/' . $this->code . ' 与 api/' . $this->code . '.ts');
            $output->writeln('  6. 编辑 ' . $this->appCode . ' 的 menus.json 注册菜单');
            $output->writeln('  7. 编辑 ' . $this->appCode . ' 的 permissions.json 注册权限');
        } else {
            $output->writeln('  1. 编辑 ' . $this->appCode . ' 的 menus.json 将插件挂载到菜单');
            $output->writeln('  2. 编辑 ' . $this->appCode . ' 的 permissions.json 注册插件权限');
            $output->writeln('  3. 编辑 admin/src/applications/' . $this->appCode . '/plugins/' . $this->code . ' 前端页面与 API');
            $output->writeln('  4. 编辑 extension/ 目录添加扩展点处理器');
            $output->writeln('  5. 按需在 event.php / queue.php 中注册事件监听与队列处理器');
        }
    }

    private function showHelp(Output $output): void
    {
        $output->writeln('<info>应用脚手架 — 一键生成完整目录和骨架代码</info>');
        $output->writeln('');
        $output->writeln('  用法:');
        $output->writeln('    php think make app <编码>    创建应用');
        $output->writeln('    php think make module <应用> <编码>  创建业务模块');
        $output->writeln('    php think make plugin <应用> <编码>  创建扩展插件');
        $output->writeln('');
        $output->writeln('  示例:');
        $output->writeln('    php think make app crm    创建 CRM 应用');
        $output->writeln('    php think make module mall notice  创建 mall 的公告模块');
        $output->writeln('    php think make plugin mall points  创建 mall 的积分插件');
        $output->writeln('');
        $output->writeln('  编码规则: 小写字母、数字、下划线，以字母开头');
    }
}