// +---------------------------------------------------------------------- declare (strict_types = 1); namespace addon\docs\controller\backend; use addon\docs\model\DocsDoc; use addon\docs\model\DocsProject; use addon\docs\model\DocsVersion; use addon\docs\service\DocSearchService; use addon\docs\service\DocTreeService; use ywxapp\controller\BackendBase; /** * 文档项目管理 * * @author ywxapp */ class Project extends BackendBase { /** * 项目列表 */ public function index() { $keyword = trim((string) $this->request->get('keyword', '')); $query = DocsProject::order('sort', 'asc')->order('id', 'asc'); if ($keyword !== '') { $query->where(function ($q) use ($keyword) { $q->whereLike('title', '%' . $keyword . '%') ->whereOr('name', 'like', '%' . $keyword . '%'); }); } $list = $query->select()->toArray(); // 附加每个项目的版本数与文档数,便于列表直观查看 foreach ($list as &$item) { $item['version_count'] = DocsVersion::where('project_id', $item['id'])->count(); $item['doc_count'] = DocsDoc::where('project_id', $item['id'])->count(); } unset($item); $this->assign('list', $list); $this->assign('keyword', $keyword); return $this->fetch('project/index'); } /** * 新增页面 */ public function add() { $this->assign('addonList', $this->addonOptions()); return $this->fetch('project/add'); } /** * 保存新增 */ public function save() { $data = $this->collect(); if (is_string($data)) { return $this->result->error($data); } if (DocsProject::where('name', $data['name'])->find()) { return $this->result->error('项目标识已存在,请更换'); } $project = DocsProject::create($data); // 新项目自动建默认版本,避免建完项目无法直接添加文档 DocsVersion::create([ 'project_id' => $project->id, 'name' => 'v1', 'title' => '默认版本', 'is_default' => 1, 'sort' => 1, 'status' => 1, ]); DocTreeService::clearCache(); return $this->result->success(null, '添加成功'); } /** * 编辑页面 * * @param int $id 项目ID */ public function edit($id = null) { $project = DocsProject::find((int) $id); if (!$project) { return $this->result->error('项目不存在'); } $this->assign('item', $project); $this->assign('addonList', $this->addonOptions()); $this->assign('versionList', DocsVersion::where('project_id', $project->id)->order('sort', 'asc')->select()); return $this->fetch('project/edit'); } /** * 保存编辑 * * @param int $id 项目ID */ public function update($id) { $project = DocsProject::find((int) $id); if (!$project) { return $this->result->error('项目不存在'); } $data = $this->collect(); if (is_string($data)) { return $this->result->error($data); } if (DocsProject::where('name', $data['name'])->where('id', '<>', $project->id)->find()) { return $this->result->error('项目标识已存在,请更换'); } $project->save($data); DocTreeService::clearCache(); return $this->result->success(null, '保存成功'); } /** * 删除项目(连同版本与文档) * * @param int $id 项目ID */ public function delete($id) { $id = (int) $id; $project = DocsProject::find($id); if (!$project) { return $this->result->error('项目不存在'); } $docIds = DocsDoc::where('project_id', $id)->column('id'); foreach ($docIds as $docId) { DocSearchService::remove((int) $docId); } DocsDoc::where('project_id', $id)->delete(); DocsVersion::where('project_id', $id)->delete(); $project->delete(); DocTreeService::clearCache(); return $this->result->success(null, '删除成功'); } /** * 收集并校验表单数据 * * @return array|string 校验失败返回错误提示字符串 */ protected function collect() { $name = trim((string) $this->request->post('name', '')); $title = trim((string) $this->request->post('title', '')); if ($name === '' || !preg_match('/^[a-z][a-z0-9_\-]{1,49}$/i', $name)) { return '项目标识只能为字母开头的字母数字组合,长度 2-50'; } if ($title === '') { return '请填写项目名称'; } return [ 'name' => $name, 'title' => $title, 'intro' => trim((string) $this->request->post('intro', '')), 'logo' => trim((string) $this->request->post('logo', '')), 'addon' => trim((string) $this->request->post('addon', '')), 'default_version' => trim((string) $this->request->post('default_version', '')), 'sort' => (int) $this->request->post('sort', 0), 'status' => (int) $this->request->post('status', 1) === 1 ? 1 : 0, ]; } /** * 扫描已安装插件,供项目归属下拉使用 * * @return array */ protected function addonOptions(): array { $dir = root_path() . 'addon'; $list = []; if (!is_dir($dir)) { return $list; } foreach ((array) scandir($dir) as $item) { if ($item === '.' || $item === '..' || !is_dir($dir . DIRECTORY_SEPARATOR . $item)) { continue; } $infoFile = $dir . DIRECTORY_SEPARATOR . $item . DIRECTORY_SEPARATOR . 'info.php'; if (!is_file($infoFile)) { continue; } $info = @include $infoFile; if (is_array($info) && !empty($info['name'])) { $list[] = [ 'name' => (string) $info['name'], 'title' => (string) ($info['title'] ?? $info['name']), ]; } } return $list; } }