保险前后端,养殖端和保险端小程序
This commit is contained in:
273
backend/examples/api-client-example.js
Normal file
273
backend/examples/api-client-example.js
Normal file
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* 前端API调用示例
|
||||
* 展示如何使用fetch方法与后端API进行交互
|
||||
*/
|
||||
|
||||
const API_BASE_URL = 'http://localhost:3000/api';
|
||||
|
||||
/**
|
||||
* 统一的API请求函数
|
||||
* @param {string} endpoint - API端点
|
||||
* @param {Object} options - 请求选项
|
||||
* @returns {Promise} API响应
|
||||
*/
|
||||
async function apiRequest(endpoint, options = {}) {
|
||||
const url = `${API_BASE_URL}${endpoint}`;
|
||||
|
||||
const defaultOptions = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
};
|
||||
|
||||
const config = {
|
||||
...defaultOptions,
|
||||
...options,
|
||||
headers: {
|
||||
...defaultOptions.headers,
|
||||
...options.headers,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(url, config);
|
||||
|
||||
// 检查响应状态
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
// 检查API响应状态
|
||||
if (result.status === 'error') {
|
||||
throw new Error(result.message || 'API请求失败');
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} catch (error) {
|
||||
console.error('API请求失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取动物列表
|
||||
* @param {Object} filters - 筛选条件
|
||||
* @param {number} page - 页码
|
||||
* @param {number} limit - 每页数量
|
||||
* @returns {Promise} 动物列表数据
|
||||
*/
|
||||
async function fetchAnimals(filters = {}, page = 1, limit = 20) {
|
||||
// 构建查询参数
|
||||
const params = new URLSearchParams({
|
||||
page: page.toString(),
|
||||
limit: limit.toString(),
|
||||
...filters
|
||||
});
|
||||
|
||||
// 移除空值参数
|
||||
Array.from(params.keys()).forEach(key => {
|
||||
if (!params.get(key)) {
|
||||
params.delete(key);
|
||||
}
|
||||
});
|
||||
|
||||
return apiRequest(`/demo/animals?${params.toString()}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备列表
|
||||
* @param {Object} filters - 筛选条件
|
||||
* @param {number} page - 页码
|
||||
* @param {number} limit - 每页数量
|
||||
* @returns {Promise} 设备列表数据
|
||||
*/
|
||||
async function fetchDevices(filters = {}, page = 1, limit = 20) {
|
||||
const params = new URLSearchParams({
|
||||
page: page.toString(),
|
||||
limit: limit.toString(),
|
||||
...filters
|
||||
});
|
||||
|
||||
// 移除空值参数
|
||||
Array.from(params.keys()).forEach(key => {
|
||||
if (!params.get(key)) {
|
||||
params.delete(key);
|
||||
}
|
||||
});
|
||||
|
||||
return apiRequest(`/demo/devices?${params.toString()}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取告警列表
|
||||
* @param {Object} filters - 筛选条件
|
||||
* @param {number} page - 页码
|
||||
* @param {number} limit - 每页数量
|
||||
* @returns {Promise} 告警列表数据
|
||||
*/
|
||||
async function fetchAlerts(filters = {}, page = 1, limit = 20) {
|
||||
const params = new URLSearchParams({
|
||||
page: page.toString(),
|
||||
limit: limit.toString(),
|
||||
...filters
|
||||
});
|
||||
|
||||
// 移除空值参数
|
||||
Array.from(params.keys()).forEach(key => {
|
||||
if (!params.get(key)) {
|
||||
params.delete(key);
|
||||
}
|
||||
});
|
||||
|
||||
return apiRequest(`/demo/alerts?${params.toString()}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取仪表盘数据
|
||||
* @returns {Promise} 仪表盘数据
|
||||
*/
|
||||
async function fetchDashboard() {
|
||||
return apiRequest('/demo/dashboard');
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新的动物
|
||||
* @param {Object} animalData - 动物数据
|
||||
* @returns {Promise} 创建结果
|
||||
*/
|
||||
async function createAnimal(animalData) {
|
||||
return apiRequest('/demo/animals', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(animalData)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新动物信息
|
||||
* @param {number} id - 动物ID
|
||||
* @param {Object} updates - 更新数据
|
||||
* @returns {Promise} 更新结果
|
||||
*/
|
||||
async function updateAnimal(id, updates) {
|
||||
return apiRequest(`/demo/animals/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(updates)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除动物
|
||||
* @param {number} id - 动物ID
|
||||
* @returns {Promise} 删除结果
|
||||
*/
|
||||
async function deleteAnimal(id) {
|
||||
return apiRequest(`/demo/animals/${id}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理告警
|
||||
* @param {number} id - 告警ID
|
||||
* @param {Object} handleData - 处理数据
|
||||
* @returns {Promise} 处理结果
|
||||
*/
|
||||
async function handleAlert(id, handleData) {
|
||||
return apiRequest(`/demo/alerts/${id}/handle`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(handleData)
|
||||
});
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
async function demo() {
|
||||
console.log('=== API调用演示 ===');
|
||||
|
||||
try {
|
||||
// 1. 获取仪表盘数据
|
||||
console.log('1. 获取仪表盘数据...');
|
||||
const dashboard = await fetchDashboard();
|
||||
console.log('仪表盘数据:', dashboard.data);
|
||||
|
||||
// 2. 获取动物列表(带筛选条件)
|
||||
console.log('\n2. 获取动物列表...');
|
||||
const animals = await fetchAnimals({
|
||||
category: 'cattle',
|
||||
status: 'active',
|
||||
minWeight: '200',
|
||||
maxWeight: '500'
|
||||
}, 1, 10);
|
||||
console.log('动物列表:', animals.data);
|
||||
console.log('总数:', animals.total);
|
||||
|
||||
// 3. 获取设备列表
|
||||
console.log('\n3. 获取设备列表...');
|
||||
const devices = await fetchDevices({
|
||||
type: 'sensor',
|
||||
status: 'online'
|
||||
}, 1, 5);
|
||||
console.log('设备列表:', devices.data);
|
||||
|
||||
// 4. 获取告警列表
|
||||
console.log('\n4. 获取告警列表...');
|
||||
const alerts = await fetchAlerts({
|
||||
level: 'high',
|
||||
status: 'pending'
|
||||
}, 1, 5);
|
||||
console.log('告警列表:', alerts.data);
|
||||
|
||||
} catch (error) {
|
||||
console.error('演示失败:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Vue 3 Composition API 使用示例
|
||||
const apiExample = {
|
||||
// 动物管理相关API
|
||||
animals: {
|
||||
fetch: fetchAnimals,
|
||||
create: createAnimal,
|
||||
update: updateAnimal,
|
||||
delete: deleteAnimal
|
||||
},
|
||||
|
||||
// 设备管理相关API
|
||||
devices: {
|
||||
fetch: fetchDevices
|
||||
},
|
||||
|
||||
// 告警管理相关API
|
||||
alerts: {
|
||||
fetch: fetchAlerts,
|
||||
handle: handleAlert
|
||||
},
|
||||
|
||||
// 统计相关API
|
||||
stats: {
|
||||
dashboard: fetchDashboard
|
||||
}
|
||||
};
|
||||
|
||||
// 导出API方法
|
||||
module.exports = {
|
||||
apiRequest,
|
||||
fetchAnimals,
|
||||
fetchDevices,
|
||||
fetchAlerts,
|
||||
fetchDashboard,
|
||||
createAnimal,
|
||||
updateAnimal,
|
||||
deleteAnimal,
|
||||
handleAlert,
|
||||
demo
|
||||
};
|
||||
|
||||
// 如果直接运行此文件,执行演示
|
||||
if (require.main === module) {
|
||||
demo();
|
||||
}
|
||||
474
backend/examples/vue3-api-example.js
Normal file
474
backend/examples/vue3-api-example.js
Normal file
@@ -0,0 +1,474 @@
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
Reference in New Issue
Block a user