474 lines
10 KiB
JavaScript
474 lines
10 KiB
JavaScript
/**
|
|
* Vue 3 Composition API 使用示例
|
|
* 展示如何在Vue组件中使用API进行数据交互
|
|
*/
|
|
|
|
import { reactive, ref, computed, onMounted } from 'vue';
|
|
import { apiExample } from './api-client-example';
|
|
|
|
/**
|
|
* 动物管理Composition函数
|
|
*/
|
|
export function useAnimals() {
|
|
const animals = ref([]);
|
|
const loading = ref(false);
|
|
const error = ref(null);
|
|
const pagination = reactive({
|
|
page: 1,
|
|
limit: 20,
|
|
total: 0,
|
|
totalPages: 0
|
|
});
|
|
|
|
const filters = reactive({
|
|
category: '',
|
|
status: '',
|
|
minWeight: '',
|
|
maxWeight: '',
|
|
search: ''
|
|
});
|
|
|
|
// 计算属性:是否有筛选条件
|
|
const hasFilters = computed(() => {
|
|
return Object.values(filters).some(value =>
|
|
value !== null && value !== undefined && value !== ''
|
|
);
|
|
});
|
|
|
|
// 获取动物列表
|
|
async function fetchAnimals() {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
try {
|
|
const result = await apiExample.animals.fetch(
|
|
{ ...filters },
|
|
pagination.page,
|
|
pagination.limit
|
|
);
|
|
|
|
animals.value = result.data;
|
|
pagination.total = result.total;
|
|
pagination.totalPages = Math.ceil(result.total / pagination.limit);
|
|
|
|
} catch (err) {
|
|
error.value = err.message;
|
|
console.error('获取动物列表失败:', err);
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
// 创建动物
|
|
async function createAnimal(animalData) {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
try {
|
|
const result = await apiExample.animals.create(animalData);
|
|
// 创建成功后刷新列表
|
|
await fetchAnimals();
|
|
return result;
|
|
} catch (err) {
|
|
error.value = err.message;
|
|
throw err;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
// 更新动物
|
|
async function updateAnimal(id, updates) {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
try {
|
|
const result = await apiExample.animals.update(id, updates);
|
|
// 更新成功后刷新列表
|
|
await fetchAnimals();
|
|
return result;
|
|
} catch (err) {
|
|
error.value = err.message;
|
|
throw err;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
// 删除动物
|
|
async function deleteAnimal(id) {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
try {
|
|
const result = await apiExample.animals.delete(id);
|
|
// 删除成功后刷新列表
|
|
await fetchAnimals();
|
|
return result;
|
|
} catch (err) {
|
|
error.value = err.message;
|
|
throw err;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
// 重置筛选条件
|
|
function resetFilters() {
|
|
Object.keys(filters).forEach(key => {
|
|
filters[key] = '';
|
|
});
|
|
pagination.page = 1;
|
|
}
|
|
|
|
// 监听筛选条件变化,使用防抖
|
|
let debounceTimer;
|
|
function onFiltersChange() {
|
|
clearTimeout(debounceTimer);
|
|
debounceTimer = setTimeout(() => {
|
|
pagination.page = 1;
|
|
fetchAnimals();
|
|
}, 300);
|
|
}
|
|
|
|
// 监听分页变化
|
|
function onPageChange(newPage) {
|
|
pagination.page = newPage;
|
|
fetchAnimals();
|
|
}
|
|
|
|
// 组件挂载时获取数据
|
|
onMounted(() => {
|
|
fetchAnimals();
|
|
});
|
|
|
|
return {
|
|
// 状态
|
|
animals,
|
|
loading,
|
|
error,
|
|
pagination,
|
|
filters,
|
|
|
|
// 计算属性
|
|
hasFilters,
|
|
|
|
// 方法
|
|
fetchAnimals,
|
|
createAnimal,
|
|
updateAnimal,
|
|
deleteAnimal,
|
|
resetFilters,
|
|
onFiltersChange,
|
|
onPageChange
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 设备管理Composition函数
|
|
*/
|
|
export function useDevices() {
|
|
const devices = ref([]);
|
|
const loading = ref(false);
|
|
const error = ref(null);
|
|
const filters = reactive({
|
|
type: '',
|
|
status: '',
|
|
search: ''
|
|
});
|
|
|
|
async function fetchDevices() {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
try {
|
|
const result = await apiExample.devices.fetch(filters);
|
|
devices.value = result.data;
|
|
} catch (err) {
|
|
error.value = err.message;
|
|
console.error('获取设备列表失败:', err);
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
fetchDevices();
|
|
});
|
|
|
|
return {
|
|
devices,
|
|
loading,
|
|
error,
|
|
filters,
|
|
fetchDevices
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 告警管理Composition函数
|
|
*/
|
|
export function useAlerts() {
|
|
const alerts = ref([]);
|
|
const loading = ref(false);
|
|
const error = ref(null);
|
|
const filters = reactive({
|
|
level: '',
|
|
status: '',
|
|
search: ''
|
|
});
|
|
|
|
async function fetchAlerts() {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
try {
|
|
const result = await apiExample.alerts.fetch(filters);
|
|
alerts.value = result.data;
|
|
} catch (err) {
|
|
error.value = err.message;
|
|
console.error('获取告警列表失败:', err);
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
async function handleAlert(id, handleData) {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
try {
|
|
const result = await apiExample.alerts.handle(id, handleData);
|
|
// 处理成功后刷新列表
|
|
await fetchAlerts();
|
|
return result;
|
|
} catch (err) {
|
|
error.value = err.message;
|
|
throw err;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
fetchAlerts();
|
|
});
|
|
|
|
return {
|
|
alerts,
|
|
loading,
|
|
error,
|
|
filters,
|
|
fetchAlerts,
|
|
handleAlert
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 仪表盘数据Composition函数
|
|
*/
|
|
export function useDashboard() {
|
|
const dashboardData = ref(null);
|
|
const loading = ref(false);
|
|
const error = ref(null);
|
|
|
|
async function fetchDashboard() {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
try {
|
|
const result = await apiExample.stats.dashboard();
|
|
dashboardData.value = result.data;
|
|
} catch (err) {
|
|
error.value = err.message;
|
|
console.error('获取仪表盘数据失败:', err);
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
fetchDashboard();
|
|
});
|
|
|
|
return {
|
|
dashboardData,
|
|
loading,
|
|
error,
|
|
fetchDashboard
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Vue组件使用示例
|
|
*/
|
|
const AnimalListComponent = {
|
|
setup() {
|
|
const {
|
|
animals,
|
|
loading,
|
|
error,
|
|
pagination,
|
|
filters,
|
|
hasFilters,
|
|
createAnimal,
|
|
updateAnimal,
|
|
deleteAnimal,
|
|
resetFilters,
|
|
onFiltersChange,
|
|
onPageChange
|
|
} = useAnimals();
|
|
|
|
// 搜索关键词
|
|
const searchKeyword = ref('');
|
|
|
|
// 监听搜索关键词变化
|
|
watch(searchKeyword, (newValue) => {
|
|
filters.search = newValue;
|
|
onFiltersChange();
|
|
});
|
|
|
|
// 处理筛选条件变化
|
|
function handleFilterChange(key, value) {
|
|
filters[key] = value;
|
|
onFiltersChange();
|
|
}
|
|
|
|
// 新建动物表单
|
|
const newAnimal = reactive({
|
|
name: '',
|
|
category: '',
|
|
weight: '',
|
|
status: 'active'
|
|
});
|
|
|
|
async function handleCreateAnimal() {
|
|
try {
|
|
await createAnimal(newAnimal);
|
|
// 清空表单
|
|
Object.keys(newAnimal).forEach(key => {
|
|
newAnimal[key] = '';
|
|
});
|
|
newAnimal.status = 'active';
|
|
} catch (error) {
|
|
// 错误处理已在useAnimals中处理
|
|
}
|
|
}
|
|
|
|
return {
|
|
animals,
|
|
loading,
|
|
error,
|
|
pagination,
|
|
filters,
|
|
hasFilters,
|
|
searchKeyword,
|
|
newAnimal,
|
|
handleFilterChange,
|
|
resetFilters,
|
|
onPageChange,
|
|
handleCreateAnimal,
|
|
updateAnimal,
|
|
deleteAnimal
|
|
};
|
|
},
|
|
|
|
template: `
|
|
<div class="animal-list">
|
|
<!-- 搜索和筛选区域 -->
|
|
<div class="filters">
|
|
<input
|
|
v-model="searchKeyword"
|
|
placeholder="搜索动物名称..."
|
|
@input="handleFilterChange('search', $event.target.value)"
|
|
/>
|
|
|
|
<select v-model="filters.category" @change="handleFilterChange('category', $event.target.value)">
|
|
<option value="">全部分类</option>
|
|
<option value="cattle">牛</option>
|
|
<option value="sheep">羊</option>
|
|
<option value="pig">猪</option>
|
|
</select>
|
|
|
|
<select v-model="filters.status" @change="handleFilterChange('status', $event.target.value)">
|
|
<option value="">全部状态</option>
|
|
<option value="active">活跃</option>
|
|
<option value="inactive">非活跃</option>
|
|
</select>
|
|
|
|
<button @click="resetFilters" :disabled="!hasFilters">
|
|
重置筛选
|
|
</button>
|
|
</div>
|
|
|
|
<!-- 加载状态 -->
|
|
<div v-if="loading" class="loading">
|
|
加载中...
|
|
</div>
|
|
|
|
<!-- 错误提示 -->
|
|
<div v-if="error" class="error">
|
|
{{ error }}
|
|
</div>
|
|
|
|
<!-- 动物列表 -->
|
|
<div v-if="!loading && !error">
|
|
<div v-if="animals.length === 0" class="empty">
|
|
暂无数据
|
|
</div>
|
|
|
|
<div v-else>
|
|
<div v-for="animal in animals" :key="animal.id" class="animal-item">
|
|
<h3>{{ animal.name }}</h3>
|
|
<p>分类: {{ animal.category }}</p>
|
|
<p>重量: {{ animal.weight }}kg</p>
|
|
<p>状态: {{ animal.status }}</p>
|
|
|
|
<button @click="updateAnimal(animal.id, { status: animal.status === 'active' ? 'inactive' : 'active' })">
|
|
{{ animal.status === 'active' ? '停用' : '启用' }}
|
|
</button>
|
|
|
|
<button @click="deleteAnimal(animal.id)">删除</button>
|
|
</div>
|
|
|
|
<!-- 分页控件 -->
|
|
<div class="pagination">
|
|
<button
|
|
@click="onPageChange(pagination.page - 1)"
|
|
:disabled="pagination.page <= 1"
|
|
>
|
|
上一页
|
|
</button>
|
|
|
|
<span>第 {{ pagination.page }} 页 / 共 {{ pagination.totalPages }} 页</span>
|
|
|
|
<button
|
|
@click="onPageChange(pagination.page + 1)"
|
|
:disabled="pagination.page >= pagination.totalPages"
|
|
>
|
|
下一页
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 新建动物表单 -->
|
|
<div class="create-form">
|
|
<h3>新建动物</h3>
|
|
<input v-model="newAnimal.name" placeholder="动物名称" />
|
|
<input v-model="newAnimal.category" placeholder="分类" />
|
|
<input v-model="newAnimal.weight" placeholder="重量" type="number" />
|
|
<button @click="handleCreateAnimal">创建</button>
|
|
</div>
|
|
</div>
|
|
`
|
|
};
|
|
|
|
// 导出所有Composition函数
|
|
module.exports = {
|
|
useAnimals,
|
|
useDevices,
|
|
useAlerts,
|
|
useDashboard,
|
|
AnimalListComponent
|
|
}; |