搜索

📄 文章 📚 合集
热门搜索
🐘 PHP ⚡ Laravel 🎨 Vue.js ⚛️ React 📦 Yii 📘 JavaScript 🗄️ MySQL 🐳 Docker
返回合集

[板块3:Vue 3 + Element Plus 后台(含认证+核心功能)] - 19 - 实现站点配置功能

代码示例
# 站点配置功能

## 1. 创建 SiteController

### 1.1 执行命令

```bash
php artisan make:controller Admin/SiteController
```

### 1.2 文件路径

`app/Http/Controllers/Admin/SiteController.php`

### 1.3 完整代码

```php
<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Site;
use Illuminate\Http\Request;

class SiteController extends Controller
{
    public function index()
    {
        $site = Site::first();
        return response()->json($site);
    }

    public function update(Request $request)
    {
        $validated = $request->validate([
            'site_name' => 'required|string|max:255',
            'site_logo' => 'nullable|string|max:500',
            'site_keywords' => 'nullable|string|max:500',
            'site_description' => 'nullable|string',
        ]);

        $site = Site::first();
        
        if ($site) {
            $site->update($validated);
        } else {
            $site = Site::create($validated);
        }
        
        return response()->json($site);
    }
}
```

### 1.4 代码说明

| 方法 | 路由 | 作用 |
|------|------|------|
| `index` | GET /api/admin/site | 获取站点配置 |
| `update` | PUT /api/admin/site | 更新站点配置 |

---

## 2. 添加 API 路由

### 2.1 文件路径

`routes/api.php`

### 2.2 完整代码

```php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Admin\AuthController;
use App\Http\Controllers\Admin\PageController;
use App\Http\Controllers\Admin\SiteController;

// 无需认证的路由
Route::post('/admin/login', [AuthController::class, 'login']);

// 需要认证的路由
Route::middleware('auth:sanctum')->prefix('admin')->group(function () {
    Route::get('/user', [AuthController::class, 'user']);
    Route::post('/logout', [AuthController::class, 'logout']);
    
    // 页面管理
    Route::get('/pages', [PageController::class, 'index']);
    Route::post('/pages', [PageController::class, 'store']);
    Route::get('/pages/{id}', [PageController::class, 'show']);
    Route::put('/pages/{id}', [PageController::class, 'update']);
    Route::delete('/pages/{id}', [PageController::class, 'destroy']);
    
    // 站点配置
    Route::get('/site', [SiteController::class, 'index']);
    Route::put('/site', [SiteController::class, 'update']);
});
```

---

## 3. 创建站点配置 API 封装

### 3.1 文件路径

`resources\js\admin\api\site.ts`

### 3.2 完整代码

```typescript
import axios from 'axios';

export interface Site {
    id: number;
    site_name: string;
    site_logo: string | null;
    site_keywords: string | null;
    site_description: string | null;
    created_at: string;
    updated_at: string;
}

export const siteApi = {
    get: () => axios.get<Site>('/api/admin/site'),
    update: (data: Partial<Site>) => axios.put<Site>('/api/admin/site', data),
};
```

### 3.3 代码说明

| 方法 | 作用 |
|------|------|
| `get` | 获取站点配置 |
| `update` | 更新站点配置 |

---

## 4. 创建站点配置 Store

### 4.1 文件路径

`resources\js\admin\stores\site.ts`

### 4.2 完整代码

```typescript
import { defineStore } from 'pinia';
import { ref } from 'vue';
import { siteApi, type Site } from '../api/site';
import { ElMessage } from 'element-plus';

export const useSiteStore = defineStore('site', () => {
    const site = ref<Site | null>(null);
    const loading = ref(false);

    const fetchSite = async () => {
        loading.value = true;
        try {
            const response = await siteApi.get();
            site.value = response.data;
        } catch (error) {
            ElMessage.error('获取站点配置失败');
        } finally {
            loading.value = false;
        }
    };

    const updateSite = async (data: Partial<Site>) => {
        loading.value = true;
        try {
            const response = await siteApi.update(data);
            site.value = response.data;
            ElMessage.success('保存成功');
            return response.data;
        } catch (error) {
            ElMessage.error('保存失败');
            throw error;
        } finally {
            loading.value = false;
        }
    };

    return {
        site,
        loading,
        fetchSite,
        updateSite,
    };
});
```

---

## 5. 修改 SiteSettings.vue 实现站点配置表单

### 5.1 文件路径

`resources\js\admin\views\SiteSettings.vue`

### 5.2 完整代码

```vue
<template>
    <div>
        <el-card v-loading="siteStore.loading">
            <template #header>
                <div>
                    <span>站点配置</span>
                    <el-button type="primary" @click="handleSubmit" :loading="submitting">
                        保存配置
                    </el-button>
                </div>
            </template>

            <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
                <el-form-item label="网站名称" prop="site_name">
                    <el-input v-model="form.site_name" placeholder="请输入网站名称" />
                </el-form-item>

                <el-form-item label="网站 Logo" prop="site_logo">
                    <el-input v-model="form.site_logo" placeholder="例如: /logo.png" />
                    <div>Logo 路径,相对于 public 目录</div>
                </el-form-item>

                <el-form-item label="SEO 关键词" prop="site_keywords">
                    <el-input
                        v-model="form.site_keywords"
                        type="textarea"
                        :rows="2"
                        placeholder="多个关键词用英文逗号分隔"
                    />
                </el-form-item>

                <el-form-item label="SEO 描述" prop="site_description">
                    <el-input
                        v-model="form.site_description"
                        type="textarea"
                        :rows="3"
                        placeholder="请输入网站描述"
                    />
                </el-form-item>
            </el-form>
        </el-card>
    </div>
</template>

<script setup>
import { ref, reactive, onMounted, watch } from 'vue';
import { useSiteStore } from '../stores/site';

const siteStore = useSiteStore();
const formRef = ref();
const submitting = ref(false);

const form = reactive({
    site_name: '',
    site_logo: '',
    site_keywords: '',
    site_description: '',
});

const rules = {
    site_name: [{ required: true, message: '请输入网站名称', trigger: 'blur' }],
};

watch(
    () => siteStore.site,
    (newSite) => {
        if (newSite) {
            form.site_name = newSite.site_name || '';
            form.site_logo = newSite.site_logo || '';
            form.site_keywords = newSite.site_keywords || '';
            form.site_description = newSite.site_description || '';
        }
    },
    { immediate: true }
);

const handleSubmit = async () => {
    if (!formRef.value) return;

    await formRef.value.validate(async (valid: boolean) => {
        if (!valid) return;

        submitting.value = true;
        try {
            await siteStore.updateSite(form);
        } finally {
            submitting.value = false;
        }
    });
};

onMounted(() => {
    siteStore.fetchSite();
});
</script>

<style scoped>
.card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.form-tip {
    font-size: 12px;
    color: #909399;
    margin-top: 4px;
}
</style>
```

### 5.3 代码说明

| 代码 | 作用 |
|------|------|
| `watch` | 监听 store 数据变化,自动更新表单 |
| `fetchSite` | 组件挂载时获取站点配置 |
| `updateSite` | 提交表单时更新站点配置 |
| `v-loading` | 加载状态显示 |
| `form-tip` | 辅助说明文字 |

---

## 6. 编译验证

### 6.1 执行命令

```bash
npm run build
```

### 6.2 预期结果

编译成功,无报错。

---

## 7. 访问测试

浏览器打开:`http://engine-api.test/admin/site`

预期结果:
- 显示站点配置表单
- 表单自动回填已有配置数据
- 修改后点击「保存配置」提示成功

---

## 8. 验证结果

| 验证项 | 预期结果 | 实际结果 |
|--------|---------|---------|
| 编译 | 无报错 | ✅ 通过 |
| 站点配置表单 | 正常显示 | ✅ 通过 |
| 数据回填 | 显示已有配置 | ✅ 通过 |
| 网站名称 | 可编辑保存 | ✅ 通过 |
| Logo 路径 | 可编辑保存 | ✅ 通过 |
| SEO 关键词 | 可编辑保存 | ✅ 通过 |
| SEO 描述 | 可编辑保存 | ✅ 通过 |
| 保存按钮 | 点击后保存成功 | ✅ 通过 |

🧸 adorable code

专注 PHP、JavaScript、Laravel、Vue.js、React、Yii 全栈开发。记录技术探索过程中的灵感与经验,分享工程实践洞见。

hello@adorablecode.com