重构动物模型和路由系统,优化查询逻辑并新增商户和促销活动功能
This commit is contained in:
431
admin-system/src/pages/animal/index.vue
Normal file
431
admin-system/src/pages/animal/index.vue
Normal file
@@ -0,0 +1,431 @@
|
||||
<template>
|
||||
<div class="animal-management">
|
||||
<a-page-header
|
||||
title="动物管理"
|
||||
subtitle="管理认养动物信息"
|
||||
:breadcrumb="{ routes: [{ path: '/dashboard', breadcrumbName: '首页' }, { path: '', breadcrumbName: '动物管理' }] }"
|
||||
>
|
||||
<template #extra>
|
||||
<a-button type="primary" @click="showCreateModal">
|
||||
<template #icon><PlusOutlined /></template>
|
||||
新增动物
|
||||
</a-button>
|
||||
</template>
|
||||
</a-page-header>
|
||||
|
||||
<a-card class="mt-4">
|
||||
<!-- 搜索区域 -->
|
||||
<div class="search-section mb-4">
|
||||
<a-form layout="inline" :model="searchForm">
|
||||
<a-form-item label="动物名称">
|
||||
<a-input v-model:value="searchForm.name" placeholder="请输入动物名称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="动物类型">
|
||||
<a-select v-model:value="searchForm.animalType" placeholder="请选择类型" style="width: 120px">
|
||||
<a-select-option value="dog">狗狗</a-select-option>
|
||||
<a-select-option value="cat">猫咪</a-select-option>
|
||||
<a-select-option value="sheep">小羊</a-select-option>
|
||||
<a-select-option value="cow">奶牛</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="状态">
|
||||
<a-select v-model:value="searchForm.status" placeholder="请选择状态" style="width: 120px">
|
||||
<a-select-option value="available">可认养</a-select-option>
|
||||
<a-select-option value="adopted">已认养</a-select-option>
|
||||
<a-select-option value="pending">审核中</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button type="primary" @click="handleSearch">
|
||||
<template #icon><SearchOutlined /></template>
|
||||
搜索
|
||||
</a-button>
|
||||
<a-button class="ml-2" @click="resetSearch">
|
||||
<template #icon><ReloadOutlined /></template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
|
||||
<!-- 表格区域 -->
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data-source="animalList"
|
||||
:pagination="pagination"
|
||||
:loading="loading"
|
||||
row-key="id"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'animalType'">
|
||||
<a-tag :color="getAnimalTypeColor(record.animalType)">
|
||||
{{ getAnimalTypeText(record.animalType) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'status'">
|
||||
<a-tag :color="getStatusColor(record.status)">
|
||||
{{ getStatusText(record.status) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<a-space>
|
||||
<a-button size="small" @click="handleView(record)">查看</a-button>
|
||||
<a-button size="small" type="primary" @click="handleEdit(record)">编辑</a-button>
|
||||
<a-button size="small" danger @click="handleDelete(record)">删除</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
|
||||
<!-- 创建/编辑模态框 -->
|
||||
<a-modal
|
||||
v-model:visible="modalVisible"
|
||||
:title="modalTitle"
|
||||
width="600px"
|
||||
:confirm-loading="confirmLoading"
|
||||
@ok="handleModalOk"
|
||||
@cancel="handleModalCancel"
|
||||
>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="formState"
|
||||
:label-col="{ span: 6 }"
|
||||
:wrapper-col="{ span: 16 }"
|
||||
:rules="rules"
|
||||
>
|
||||
<a-form-item label="动物名称" name="name">
|
||||
<a-input v-model:value="formState.name" placeholder="请输入动物名称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="动物类型" name="animalType">
|
||||
<a-select v-model:value="formState.animalType" placeholder="请选择动物类型">
|
||||
<a-select-option value="dog">狗狗</a-select-option>
|
||||
<a-select-option value="cat">猫咪</a-select-option>
|
||||
<a-select-option value="sheep">小羊</a-select-option>
|
||||
<a-select-option value="cow">奶牛</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="品种" name="breed">
|
||||
<a-input v-model:value="formState.breed" placeholder="请输入品种" />
|
||||
</a-form-item>
|
||||
<a-form-item label="年龄" name="age">
|
||||
<a-input-number v-model:value="formState.age" :min="0" :max="30" placeholder="请输入年龄" />
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" name="status">
|
||||
<a-select v-model:value="formState.status" placeholder="请选择状态">
|
||||
<a-select-option value="available">可认养</a-select-option>
|
||||
<a-select-option value="adopted">已认养</a-select-option>
|
||||
<a-select-option value="pending">审核中</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="描述" name="description">
|
||||
<a-textarea
|
||||
v-model:value="formState.description"
|
||||
placeholder="请输入动物描述"
|
||||
:rows="4"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { message, type FormInstance } from 'ant-design-vue'
|
||||
import {
|
||||
PlusOutlined,
|
||||
SearchOutlined,
|
||||
ReloadOutlined
|
||||
} from '@ant-design/icons-vue'
|
||||
|
||||
interface Animal {
|
||||
id: number
|
||||
name: string
|
||||
animalType: string
|
||||
breed: string
|
||||
age: number
|
||||
status: string
|
||||
description: string
|
||||
createTime: string
|
||||
}
|
||||
|
||||
interface SearchForm {
|
||||
name?: string
|
||||
animalType?: string
|
||||
status?: string
|
||||
}
|
||||
|
||||
interface FormState {
|
||||
name: string
|
||||
animalType: string
|
||||
breed: string
|
||||
age: number
|
||||
status: string
|
||||
description: string
|
||||
}
|
||||
|
||||
// 表格列配置
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '动物名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name'
|
||||
},
|
||||
{
|
||||
title: '动物类型',
|
||||
key: 'animalType',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '品种',
|
||||
dataIndex: 'breed',
|
||||
key: 'breed'
|
||||
},
|
||||
{
|
||||
title: '年龄',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
fixed: 'right'
|
||||
}
|
||||
]
|
||||
|
||||
// 响应式数据
|
||||
const animalList = ref<Animal[]>([])
|
||||
const loading = ref(false)
|
||||
const modalVisible = ref(false)
|
||||
const confirmLoading = ref(false)
|
||||
const formRef = ref<FormInstance>()
|
||||
const isEdit = ref(false)
|
||||
const editingId = ref<number>()
|
||||
|
||||
const searchForm = reactive<SearchForm>({})
|
||||
const formState = reactive<FormState>({
|
||||
name: '',
|
||||
animalType: '',
|
||||
breed: '',
|
||||
age: 0,
|
||||
status: '',
|
||||
description: ''
|
||||
})
|
||||
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total: number) => `共 ${total} 条记录`
|
||||
})
|
||||
|
||||
const rules = {
|
||||
name: [{ required: true, message: '请输入动物名称', trigger: 'blur' }],
|
||||
animalType: [{ required: true, message: '请选择动物类型', trigger: 'change' }],
|
||||
status: [{ required: true, message: '请选择状态', trigger: 'change' }]
|
||||
}
|
||||
|
||||
const modalTitle = computed(() => isEdit.value ? '编辑动物' : '新增动物')
|
||||
|
||||
// 方法
|
||||
const getAnimalTypeText = (type: string) => {
|
||||
const map: Record<string, string> = {
|
||||
dog: '狗狗',
|
||||
cat: '猫咪',
|
||||
sheep: '小羊',
|
||||
cow: '奶牛'
|
||||
}
|
||||
return map[type] || type
|
||||
}
|
||||
|
||||
const getAnimalTypeColor = (type: string) => {
|
||||
const map: Record<string, string> = {
|
||||
dog: 'blue',
|
||||
cat: 'pink',
|
||||
sheep: 'green',
|
||||
cow: 'orange'
|
||||
}
|
||||
return map[type] || 'default'
|
||||
}
|
||||
|
||||
const getStatusText = (status: string) => {
|
||||
const map: Record<string, string> = {
|
||||
available: '可认养',
|
||||
adopted: '已认养',
|
||||
pending: '审核中'
|
||||
}
|
||||
return map[status] || status
|
||||
}
|
||||
|
||||
const getStatusColor = (status: string) => {
|
||||
const map: Record<string, string> = {
|
||||
available: 'green',
|
||||
adopted: 'red',
|
||||
pending: 'orange'
|
||||
}
|
||||
return map[status] || 'default'
|
||||
}
|
||||
|
||||
const fetchAnimals = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// 模拟数据
|
||||
animalList.value = [
|
||||
{
|
||||
id: 1,
|
||||
name: '小白',
|
||||
animalType: 'dog',
|
||||
breed: '萨摩耶',
|
||||
age: 2,
|
||||
status: 'available',
|
||||
description: '温顺可爱的萨摩耶',
|
||||
createTime: '2024-01-15 10:30:00'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '小花',
|
||||
animalType: 'cat',
|
||||
breed: '英短',
|
||||
age: 1,
|
||||
status: 'adopted',
|
||||
description: '活泼好动的英短猫',
|
||||
createTime: '2024-01-16 14:20:00'
|
||||
}
|
||||
]
|
||||
pagination.total = animalList.value.length
|
||||
} catch (error) {
|
||||
message.error('获取动物列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.current = 1
|
||||
fetchAnimals()
|
||||
}
|
||||
|
||||
const resetSearch = () => {
|
||||
Object.assign(searchForm, {
|
||||
name: undefined,
|
||||
animalType: undefined,
|
||||
status: undefined
|
||||
})
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
const handleTableChange = (pag: any) => {
|
||||
pagination.current = pag.current
|
||||
pagination.pageSize = pag.pageSize
|
||||
fetchAnimals()
|
||||
}
|
||||
|
||||
const showCreateModal = () => {
|
||||
isEdit.value = false
|
||||
editingId.value = undefined
|
||||
Object.assign(formState, {
|
||||
name: '',
|
||||
animalType: '',
|
||||
breed: '',
|
||||
age: 0,
|
||||
status: '',
|
||||
description: ''
|
||||
})
|
||||
modalVisible.value = true
|
||||
}
|
||||
|
||||
const handleEdit = (record: Animal) => {
|
||||
isEdit.value = true
|
||||
editingId.value = record.id
|
||||
Object.assign(formState, record)
|
||||
modalVisible.value = true
|
||||
}
|
||||
|
||||
const handleView = (record: Animal) => {
|
||||
// 查看详情逻辑
|
||||
message.info(`查看动物: ${record.name}`)
|
||||
}
|
||||
|
||||
const handleDelete = (record: Animal) => {
|
||||
// 删除逻辑
|
||||
message.warning(`删除动物: ${record.name}`)
|
||||
}
|
||||
|
||||
const handleModalOk = async () => {
|
||||
try {
|
||||
await formRef.value?.validate()
|
||||
confirmLoading.value = true
|
||||
|
||||
if (isEdit.value) {
|
||||
// 编辑逻辑
|
||||
message.success('编辑成功')
|
||||
} else {
|
||||
// 新增逻辑
|
||||
message.success('新增成功')
|
||||
}
|
||||
|
||||
modalVisible.value = false
|
||||
fetchAnimals()
|
||||
} catch (error) {
|
||||
console.error('表单验证失败', error)
|
||||
} finally {
|
||||
confirmLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleModalCancel = () => {
|
||||
modalVisible.value = false
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
fetchAnimals()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.animal-management {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.search-section {
|
||||
background: #fafafa;
|
||||
padding: 16px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.mt-4 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.ml-2 {
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,4 +1,4 @@
|
||||
const db = require('../config/database');
|
||||
const { query } = require('../config/database');
|
||||
|
||||
/**
|
||||
* 动物模型类
|
||||
@@ -12,7 +12,7 @@ class Animal {
|
||||
*/
|
||||
static async findById(id) {
|
||||
try {
|
||||
const [rows] = await db.execute(
|
||||
const [rows] = await query(
|
||||
'SELECT * FROM animals WHERE id = ?',
|
||||
[id]
|
||||
);
|
||||
@@ -52,7 +52,7 @@ class Animal {
|
||||
LIMIT ? OFFSET ?
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [...params, limit, offset]);
|
||||
const [rows] = await query(query, [...params, limit, offset]);
|
||||
return rows;
|
||||
} catch (error) {
|
||||
console.error('获取动物列表失败:', error);
|
||||
@@ -75,7 +75,7 @@ class Animal {
|
||||
WHERE 1=1 ${whereClause}
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, params);
|
||||
const [rows] = await query(query, params);
|
||||
return rows[0].count;
|
||||
} catch (error) {
|
||||
console.error('获取动物数量失败:', error);
|
||||
@@ -102,7 +102,7 @@ class Animal {
|
||||
WHERE a.id = ?
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [id]);
|
||||
const [rows] = await query(query, [id]);
|
||||
return rows[0] || null;
|
||||
} catch (error) {
|
||||
console.error('获取动物详情失败:', error);
|
||||
@@ -126,11 +126,11 @@ class Animal {
|
||||
WHERE id = ?
|
||||
`;
|
||||
|
||||
const [result] = await db.execute(query, [status, id]);
|
||||
const [result] = await query(query, [status, id]);
|
||||
|
||||
// 记录状态变更日志
|
||||
if (reason) {
|
||||
await db.execute(
|
||||
await query(
|
||||
`INSERT INTO animal_status_logs (animal_id, old_status, new_status, admin_id, reason, created_at)
|
||||
SELECT ?, status, ?, ?, ?, NOW() FROM animals WHERE id = ?`,
|
||||
[id, status, adminId, reason, id]
|
||||
@@ -161,7 +161,7 @@ class Animal {
|
||||
WHERE id IN (${placeholders})
|
||||
`;
|
||||
|
||||
const [result] = await db.execute(query, [status, ...ids]);
|
||||
const [result] = await query(query, [status, ...ids]);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('批量更新动物状态失败:', error);
|
||||
@@ -187,7 +187,7 @@ class Animal {
|
||||
FROM animals
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query);
|
||||
const [rows] = await query(query);
|
||||
return rows[0];
|
||||
} catch (error) {
|
||||
console.error('获取动物总体统计失败:', error);
|
||||
@@ -212,7 +212,7 @@ class Animal {
|
||||
ORDER BY count DESC
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query);
|
||||
const [rows] = await query(query);
|
||||
return rows;
|
||||
} catch (error) {
|
||||
console.error('获取动物统计信息失败:', error);
|
||||
@@ -236,7 +236,7 @@ class Animal {
|
||||
ORDER BY count DESC
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query);
|
||||
const [rows] = await query(query);
|
||||
return rows;
|
||||
} catch (error) {
|
||||
console.error('获取按状态分类的统计失败:', error);
|
||||
@@ -264,7 +264,7 @@ class Animal {
|
||||
ORDER BY animal_count DESC
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query);
|
||||
const [rows] = await query(query);
|
||||
return rows;
|
||||
} catch (error) {
|
||||
console.error('获取按商家分类的统计失败:', error);
|
||||
@@ -290,7 +290,7 @@ class Animal {
|
||||
ORDER BY month ASC
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query);
|
||||
const [rows] = await query(query);
|
||||
return rows;
|
||||
} catch (error) {
|
||||
console.error('获取月度趋势数据失败:', error);
|
||||
@@ -325,7 +325,7 @@ class Animal {
|
||||
ORDER BY a.created_at DESC
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, params);
|
||||
const [rows] = await query(query, params);
|
||||
return rows;
|
||||
} catch (error) {
|
||||
console.error('获取导出数据失败:', error);
|
||||
@@ -366,7 +366,7 @@ class Animal {
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
|
||||
`;
|
||||
|
||||
const [result] = await db.execute(query, [
|
||||
const [result] = await query(query, [
|
||||
name, type, breed, age, gender, weight, price,
|
||||
description, health_status, JSON.stringify(vaccination_records || []),
|
||||
JSON.stringify(images || []), merchant_id, farm_location,
|
||||
@@ -406,7 +406,7 @@ class Animal {
|
||||
values.push(id);
|
||||
|
||||
const query = `UPDATE animals SET ${fields.join(', ')} WHERE id = ?`;
|
||||
const [result] = await db.execute(query, values);
|
||||
const [result] = await query(query, values);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
@@ -422,7 +422,7 @@ class Animal {
|
||||
*/
|
||||
static async delete(id) {
|
||||
try {
|
||||
const [result] = await db.execute('DELETE FROM animals WHERE id = ?', [id]);
|
||||
const [result] = await query('DELETE FROM animals WHERE id = ?', [id]);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('删除动物失败:', error);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const db = require('../config/database');
|
||||
const { query } = require('../config/database');
|
||||
|
||||
class AnimalClaim {
|
||||
/**
|
||||
@@ -26,7 +26,7 @@ class AnimalClaim {
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
|
||||
`;
|
||||
|
||||
const [result] = await db.execute(query, [
|
||||
const [result] = await query(query, [
|
||||
claim_no,
|
||||
animal_id,
|
||||
user_id,
|
||||
@@ -68,7 +68,7 @@ class AnimalClaim {
|
||||
WHERE ac.id = ? AND ac.deleted_at IS NULL
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [id]);
|
||||
const [rows] = await query(query, [id]);
|
||||
return rows[0] || null;
|
||||
} catch (error) {
|
||||
console.error('查找认领申请数据库错误:', error);
|
||||
@@ -97,7 +97,7 @@ class AnimalClaim {
|
||||
WHERE ac.claim_no = ? AND ac.deleted_at IS NULL
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [claimNo]);
|
||||
const [rows] = await query(query, [claimNo]);
|
||||
return rows[0] || null;
|
||||
} catch (error) {
|
||||
console.error('根据订单号查找认领申请数据库错误:', error);
|
||||
@@ -122,7 +122,7 @@ class AnimalClaim {
|
||||
LIMIT 1
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [userId, animalId]);
|
||||
const [rows] = await query(query, [userId, animalId]);
|
||||
return rows[0] || null;
|
||||
} catch (error) {
|
||||
console.error('查找活跃认领申请数据库错误:', error);
|
||||
@@ -158,7 +158,7 @@ class AnimalClaim {
|
||||
WHERE id = ?
|
||||
`;
|
||||
|
||||
await db.execute(query, values);
|
||||
await query(query, values);
|
||||
return await this.findById(id);
|
||||
} catch (error) {
|
||||
console.error('更新认领申请状态数据库错误:', error);
|
||||
@@ -225,7 +225,7 @@ class AnimalClaim {
|
||||
LIMIT ? OFFSET ?
|
||||
`;
|
||||
|
||||
const [dataRows] = await db.execute(dataQuery, [...queryParams, limit, offset]);
|
||||
const [dataRows] = await query(dataQuery, [...queryParams, limit, offset]);
|
||||
|
||||
// 查询总数
|
||||
const countQuery = `
|
||||
@@ -235,7 +235,7 @@ class AnimalClaim {
|
||||
WHERE ${whereClause}
|
||||
`;
|
||||
|
||||
const [countRows] = await db.execute(countQuery, queryParams);
|
||||
const [countRows] = await query(countQuery, queryParams);
|
||||
const total = countRows[0].total;
|
||||
|
||||
return {
|
||||
@@ -292,7 +292,7 @@ class AnimalClaim {
|
||||
LIMIT ? OFFSET ?
|
||||
`;
|
||||
|
||||
const [dataRows] = await db.execute(dataQuery, [...queryParams, limit, offset]);
|
||||
const [dataRows] = await query(dataQuery, [...queryParams, limit, offset]);
|
||||
|
||||
// 查询总数
|
||||
const countQuery = `
|
||||
@@ -301,7 +301,7 @@ class AnimalClaim {
|
||||
WHERE ${whereClause}
|
||||
`;
|
||||
|
||||
const [countRows] = await db.execute(countQuery, queryParams);
|
||||
const [countRows] = await query(countQuery, queryParams);
|
||||
const total = countRows[0].total;
|
||||
|
||||
return {
|
||||
@@ -396,7 +396,7 @@ class AnimalClaim {
|
||||
LIMIT ? OFFSET ?
|
||||
`;
|
||||
|
||||
const [dataRows] = await db.execute(dataQuery, [...queryParams, limit, offset]);
|
||||
const [dataRows] = await query(dataQuery, [...queryParams, limit, offset]);
|
||||
|
||||
// 查询总数
|
||||
const countQuery = `
|
||||
@@ -407,7 +407,7 @@ class AnimalClaim {
|
||||
WHERE ${whereClause}
|
||||
`;
|
||||
|
||||
const [countRows] = await db.execute(countQuery, queryParams);
|
||||
const [countRows] = await query(countQuery, queryParams);
|
||||
const total = countRows[0].total;
|
||||
|
||||
return {
|
||||
@@ -446,7 +446,7 @@ class AnimalClaim {
|
||||
) VALUES (?, ?, ?, ?, ?, NOW(), NOW())
|
||||
`;
|
||||
|
||||
const [result] = await db.execute(query, [
|
||||
const [result] = await query(query, [
|
||||
claim_id,
|
||||
duration,
|
||||
amount,
|
||||
@@ -511,7 +511,7 @@ class AnimalClaim {
|
||||
WHERE ${whereClause}
|
||||
`;
|
||||
|
||||
const [basicStats] = await db.execute(basicStatsQuery, queryParams);
|
||||
const [basicStats] = await query(basicStatsQuery, queryParams);
|
||||
|
||||
// 按动物类型统计
|
||||
const typeStatsQuery = `
|
||||
@@ -527,7 +527,7 @@ class AnimalClaim {
|
||||
ORDER BY claim_count DESC
|
||||
`;
|
||||
|
||||
const [typeStats] = await db.execute(typeStatsQuery, queryParams);
|
||||
const [typeStats] = await query(typeStatsQuery, queryParams);
|
||||
|
||||
// 按月份统计
|
||||
const monthlyStatsQuery = `
|
||||
@@ -544,7 +544,7 @@ class AnimalClaim {
|
||||
LIMIT 12
|
||||
`;
|
||||
|
||||
const [monthlyStats] = await db.execute(monthlyStatsQuery, queryParams);
|
||||
const [monthlyStats] = await query(monthlyStatsQuery, queryParams);
|
||||
|
||||
return {
|
||||
basic: basicStats[0],
|
||||
@@ -570,7 +570,7 @@ class AnimalClaim {
|
||||
WHERE id = ?
|
||||
`;
|
||||
|
||||
const [result] = await db.execute(query, [id]);
|
||||
const [result] = await query(query, [id]);
|
||||
return result.affectedRows > 0;
|
||||
} catch (error) {
|
||||
console.error('软删除认领申请数据库错误:', error);
|
||||
|
||||
@@ -9,7 +9,7 @@ class Merchant {
|
||||
static async findById(id) {
|
||||
try {
|
||||
const sql = 'SELECT * FROM merchants WHERE id = ?';
|
||||
const [rows] = await query(sql, [id]);
|
||||
const rows = await query(sql, [id]);
|
||||
return rows.length > 0 ? rows[0] : null;
|
||||
} catch (error) {
|
||||
console.error('查找商户失败:', error);
|
||||
@@ -53,17 +53,12 @@ class Merchant {
|
||||
|
||||
// 查询总数
|
||||
const countSql = `SELECT COUNT(*) as total FROM merchants ${whereClause}`;
|
||||
const [countResult] = await query(countSql, params);
|
||||
const total = countResult[0].total;
|
||||
const countResult = await query(countSql, params);
|
||||
const total = countResult && countResult.length > 0 ? countResult[0].total : 0;
|
||||
|
||||
// 查询数据
|
||||
const dataSql = `
|
||||
SELECT * FROM merchants
|
||||
${whereClause}
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`;
|
||||
const [rows] = await query(dataSql, [...params, limit, offset]);
|
||||
const dataSql = `SELECT * FROM merchants ${whereClause} ORDER BY created_at DESC LIMIT ${parseInt(limit)} OFFSET ${parseInt(offset)}`;
|
||||
const rows = await query(dataSql, params);
|
||||
|
||||
return {
|
||||
data: rows,
|
||||
@@ -99,7 +94,7 @@ class Merchant {
|
||||
`;
|
||||
|
||||
const params = [name, type, contact_person, contact_phone, email, address, description];
|
||||
const [result] = await query(sql, params);
|
||||
const result = await query(sql, params);
|
||||
|
||||
// 返回创建的商户信息
|
||||
return await this.findById(result.insertId);
|
||||
@@ -133,7 +128,7 @@ class Merchant {
|
||||
params.push(id);
|
||||
|
||||
const sql = `UPDATE merchants SET ${updateFields.join(', ')} WHERE id = ?`;
|
||||
const [result] = await query(sql, params);
|
||||
const result = await query(sql, params);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
throw new Error('商户不存在或更新失败');
|
||||
@@ -151,7 +146,7 @@ class Merchant {
|
||||
static async delete(id) {
|
||||
try {
|
||||
const sql = 'DELETE FROM merchants WHERE id = ?';
|
||||
const [result] = await query(sql, [id]);
|
||||
const result = await query(sql, [id]);
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
throw new Error('商户不存在或删除失败');
|
||||
@@ -174,16 +169,16 @@ class Merchant {
|
||||
|
||||
// 获取关联的动物数量
|
||||
const animalCountSql = 'SELECT COUNT(*) as count FROM animals WHERE merchant_id = ?';
|
||||
const [animalResult] = await query(animalCountSql, [id]);
|
||||
const animalResult = await query(animalCountSql, [id]);
|
||||
|
||||
// 获取关联的订单数量
|
||||
const orderCountSql = 'SELECT COUNT(*) as count FROM orders WHERE merchant_id = ?';
|
||||
const [orderResult] = await query(orderCountSql, [id]);
|
||||
const orderResult = await query(orderCountSql, [id]);
|
||||
|
||||
return {
|
||||
...merchant,
|
||||
animal_count: animalResult[0].count,
|
||||
order_count: orderResult[0].count
|
||||
animal_count: animalResult && animalResult.length > 0 ? animalResult[0].count : 0,
|
||||
order_count: orderResult && orderResult.length > 0 ? orderResult[0].count : 0
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('获取商户详情失败:', error);
|
||||
@@ -205,7 +200,7 @@ class Merchant {
|
||||
FROM merchants
|
||||
`;
|
||||
|
||||
const [rows] = await query(sql);
|
||||
const rows = await query(sql);
|
||||
return rows[0];
|
||||
} catch (error) {
|
||||
console.error('获取商户统计信息失败:', error);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const db = require('../config/database');
|
||||
const { query } = require('../config/database');
|
||||
|
||||
class Payment {
|
||||
/**
|
||||
@@ -24,7 +24,7 @@ class Payment {
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', NOW(), NOW())
|
||||
`;
|
||||
|
||||
const [result] = await db.execute(query, [
|
||||
const [result] = await query(query, [
|
||||
payment_no, order_id, user_id, amount, payment_method,
|
||||
return_url, notify_url
|
||||
]);
|
||||
@@ -46,7 +46,7 @@ class Payment {
|
||||
WHERE p.id = ? AND p.deleted_at IS NULL
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [id]);
|
||||
const [rows] = await query(query, [id]);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class Payment {
|
||||
WHERE p.payment_no = ? AND p.deleted_at IS NULL
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [paymentNo]);
|
||||
const [rows] = await query(query, [paymentNo]);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ class Payment {
|
||||
ORDER BY created_at DESC
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [orderId]);
|
||||
const [rows] = await query(query, [orderId]);
|
||||
return rows;
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ class Payment {
|
||||
WHERE id = ? AND deleted_at IS NULL
|
||||
`;
|
||||
|
||||
await db.execute(query, [
|
||||
await query(query, [
|
||||
status, transaction_id, paid_amount,
|
||||
paid_at, failure_reason, id
|
||||
]);
|
||||
@@ -163,7 +163,7 @@ class Payment {
|
||||
FROM payments p
|
||||
WHERE ${whereClause}
|
||||
`;
|
||||
const [countResult] = await db.execute(countQuery, params);
|
||||
const [countResult] = await query(countQuery, params);
|
||||
const total = countResult[0].total;
|
||||
|
||||
// 查询数据
|
||||
@@ -176,7 +176,7 @@ class Payment {
|
||||
LIMIT ? OFFSET ?
|
||||
`;
|
||||
params.push(limit, offset);
|
||||
const [rows] = await db.execute(dataQuery, params);
|
||||
const [rows] = await query(dataQuery, params);
|
||||
|
||||
return {
|
||||
data: rows,
|
||||
@@ -252,7 +252,7 @@ class Payment {
|
||||
LEFT JOIN users u ON p.user_id = u.id
|
||||
WHERE ${whereClause}
|
||||
`;
|
||||
const [countResult] = await db.execute(countQuery, params);
|
||||
const [countResult] = await query(countQuery, params);
|
||||
const total = countResult[0].total;
|
||||
|
||||
// 查询数据
|
||||
@@ -267,7 +267,7 @@ class Payment {
|
||||
LIMIT ? OFFSET ?
|
||||
`;
|
||||
params.push(limit, offset);
|
||||
const [rows] = await db.execute(dataQuery, params);
|
||||
const [rows] = await query(dataQuery, params);
|
||||
|
||||
return {
|
||||
data: rows,
|
||||
@@ -301,7 +301,7 @@ class Payment {
|
||||
) VALUES (?, ?, ?, ?, ?, 'pending', NOW(), NOW())
|
||||
`;
|
||||
|
||||
const [result] = await db.execute(query, [
|
||||
const [result] = await query(query, [
|
||||
refund_no, payment_id, user_id, refund_amount, refund_reason
|
||||
]);
|
||||
|
||||
@@ -325,7 +325,7 @@ class Payment {
|
||||
WHERE r.id = ? AND r.deleted_at IS NULL
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [id]);
|
||||
const [rows] = await query(query, [id]);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ class Payment {
|
||||
WHERE id = ? AND deleted_at IS NULL
|
||||
`;
|
||||
|
||||
await db.execute(query, [
|
||||
await query(query, [
|
||||
status, processed_by, process_remark,
|
||||
refund_transaction_id, refunded_at, id
|
||||
]);
|
||||
@@ -402,7 +402,7 @@ class Payment {
|
||||
FROM payments
|
||||
WHERE ${whereClause}
|
||||
`;
|
||||
const [totalResult] = await db.execute(totalQuery, params);
|
||||
const [totalResult] = await query(totalQuery, params);
|
||||
|
||||
// 退款统计
|
||||
const refundQuery = `
|
||||
@@ -421,7 +421,7 @@ class Payment {
|
||||
if (end_date) refundParams.push(end_date);
|
||||
if (payment_method) refundParams.push(payment_method);
|
||||
|
||||
const [refundResult] = await db.execute(refundQuery, refundParams);
|
||||
const [refundResult] = await query(refundQuery, refundParams);
|
||||
|
||||
// 按支付方式统计
|
||||
const methodQuery = `
|
||||
@@ -433,7 +433,7 @@ class Payment {
|
||||
WHERE ${whereClause}
|
||||
GROUP BY payment_method
|
||||
`;
|
||||
const [methodResult] = await db.execute(methodQuery, params);
|
||||
const [methodResult] = await query(methodQuery, params);
|
||||
|
||||
return {
|
||||
total_count: totalResult[0].total_count,
|
||||
@@ -457,7 +457,7 @@ class Payment {
|
||||
*/
|
||||
static async exists(id) {
|
||||
const query = 'SELECT 1 FROM payments WHERE id = ? AND deleted_at IS NULL';
|
||||
const [rows] = await db.execute(query, [id]);
|
||||
const [rows] = await query(query, [id]);
|
||||
return rows.length > 0;
|
||||
}
|
||||
|
||||
@@ -473,7 +473,7 @@ class Payment {
|
||||
WHERE id = ? AND deleted_at IS NULL
|
||||
`;
|
||||
|
||||
const [result] = await db.execute(query, [id]);
|
||||
const [result] = await query(query, [id]);
|
||||
return result.affectedRows > 0;
|
||||
}
|
||||
|
||||
@@ -491,7 +491,7 @@ class Payment {
|
||||
AND deleted_at IS NULL
|
||||
`;
|
||||
|
||||
const [result] = await db.execute(query, [hours]);
|
||||
const [result] = await query(query, [hours]);
|
||||
return result.affectedRows;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ class Travel {
|
||||
SET current_participants = GREATEST(0, current_participants - ?), updated_at = NOW()
|
||||
WHERE id = ?
|
||||
`;
|
||||
const [result] = await query(sql, [count, id]);
|
||||
const [result] = await query(query, [count, id]);
|
||||
return result.affectedRows > 0;
|
||||
}
|
||||
|
||||
@@ -372,7 +372,7 @@ class Travel {
|
||||
FROM travel_plans
|
||||
WHERE id = ?
|
||||
`;
|
||||
const [rows] = await query(sql, [id]);
|
||||
const [rows] = await query(query, [id]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return false;
|
||||
@@ -403,7 +403,7 @@ class Travel {
|
||||
LIMIT ?
|
||||
`;
|
||||
|
||||
const [rows] = await query(sql, [limit]);
|
||||
const [rows] = await query(query, [limit]);
|
||||
|
||||
// 解析JSON字段
|
||||
return rows.map(travel => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const db = require('../config/database');
|
||||
const { query } = require('../config/database');
|
||||
|
||||
/**
|
||||
* 旅行报名数据模型
|
||||
@@ -25,7 +25,7 @@ class TravelRegistration {
|
||||
VALUES (?, ?, ?, ?, ?, 'pending', NOW())
|
||||
`;
|
||||
|
||||
const [result] = await db.execute(query, [
|
||||
const [result] = await query(query, [
|
||||
travel_plan_id,
|
||||
user_id,
|
||||
message || null,
|
||||
@@ -58,7 +58,7 @@ class TravelRegistration {
|
||||
WHERE tr.id = ?
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [id]);
|
||||
const [rows] = await query(query, [id]);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ class TravelRegistration {
|
||||
WHERE user_id = ? AND travel_plan_id = ? AND status != 'cancelled'
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [userId, travelPlanId]);
|
||||
const [rows] = await query(query, [userId, travelPlanId]);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ class TravelRegistration {
|
||||
FROM travel_registrations tr
|
||||
${whereClause}
|
||||
`;
|
||||
const [countResult] = await db.execute(countQuery, params);
|
||||
const [countResult] = await query(countQuery, params);
|
||||
const total = countResult[0].total;
|
||||
|
||||
// 获取数据
|
||||
@@ -127,7 +127,7 @@ class TravelRegistration {
|
||||
`;
|
||||
|
||||
params.push(pageSize, offset);
|
||||
const [rows] = await db.execute(query, params);
|
||||
const [rows] = await query(query, params);
|
||||
|
||||
return {
|
||||
registrations: rows,
|
||||
@@ -168,7 +168,7 @@ class TravelRegistration {
|
||||
FROM travel_registrations tr
|
||||
${whereClause}
|
||||
`;
|
||||
const [countResult] = await db.execute(countQuery, params);
|
||||
const [countResult] = await query(countQuery, params);
|
||||
const total = countResult[0].total;
|
||||
|
||||
// 获取数据
|
||||
@@ -188,7 +188,7 @@ class TravelRegistration {
|
||||
`;
|
||||
|
||||
params.push(pageSize, offset);
|
||||
const [rows] = await db.execute(query, params);
|
||||
const [rows] = await query(query, params);
|
||||
|
||||
return {
|
||||
registrations: rows,
|
||||
@@ -215,7 +215,7 @@ class TravelRegistration {
|
||||
WHERE id = ?
|
||||
`;
|
||||
|
||||
await db.execute(query, [status, rejectReason, id]);
|
||||
await query(query, [status, rejectReason, id]);
|
||||
return this.findById(id);
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ class TravelRegistration {
|
||||
WHERE travel_plan_id = ?
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [travelPlanId]);
|
||||
const [rows] = await query(query, [travelPlanId]);
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ class TravelRegistration {
|
||||
WHERE id = ? AND created_by = ?
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [travelPlanId, userId]);
|
||||
const [rows] = await query(query, [travelPlanId, userId]);
|
||||
return rows.length > 0;
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ class TravelRegistration {
|
||||
WHERE tr.id = ? AND tp.created_by = ?
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [registrationId, userId]);
|
||||
const [rows] = await query(query, [registrationId, userId]);
|
||||
return rows.length > 0;
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ class TravelRegistration {
|
||||
WHERE travel_plan_id = ? AND status = 'approved'
|
||||
`;
|
||||
|
||||
const [rows] = await db.execute(query, [travelPlanId]);
|
||||
const [rows] = await query(query, [travelPlanId]);
|
||||
return rows[0].count;
|
||||
}
|
||||
|
||||
|
||||
@@ -342,7 +342,8 @@ class OrderService {
|
||||
pageSize = 10,
|
||||
status,
|
||||
merchantId,
|
||||
userId
|
||||
userId,
|
||||
order_no
|
||||
} = filters;
|
||||
const offset = (page - 1) * pageSize;
|
||||
|
||||
@@ -390,6 +391,13 @@ class OrderService {
|
||||
countParams.push(userId);
|
||||
}
|
||||
|
||||
if (order_no) {
|
||||
query += ' AND o.order_no = ?';
|
||||
countQuery += ' AND o.order_no = ?';
|
||||
params.push(order_no);
|
||||
countParams.push(order_no);
|
||||
}
|
||||
|
||||
query += ' ORDER BY o.created_at DESC LIMIT ? OFFSET ?';
|
||||
params.push(pageSize, offset);
|
||||
|
||||
@@ -410,6 +418,36 @@ class OrderService {
|
||||
throw new Error('获取所有订单失败');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单统计信息(管理员)
|
||||
* @returns {Promise<Object>} 统计信息
|
||||
*/
|
||||
async getOrderStatistics() {
|
||||
try {
|
||||
const query = `
|
||||
SELECT
|
||||
COUNT(*) as total_orders,
|
||||
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending_orders,
|
||||
SUM(CASE WHEN status = 'paid' THEN 1 ELSE 0 END) as paid_orders,
|
||||
SUM(CASE WHEN status = 'processing' THEN 1 ELSE 0 END) as processing_orders,
|
||||
SUM(CASE WHEN status = 'shipped' THEN 1 ELSE 0 END) as shipped_orders,
|
||||
SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed_orders,
|
||||
SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0 END) as cancelled_orders,
|
||||
SUM(CASE WHEN status = 'refunded' THEN 1 ELSE 0 END) as refunded_orders,
|
||||
SUM(total_amount) as total_revenue
|
||||
FROM orders
|
||||
WHERE is_deleted = 0
|
||||
`;
|
||||
|
||||
const [stats] = await database.query(query);
|
||||
|
||||
return stats;
|
||||
} catch (error) {
|
||||
console.error('获取订单统计失败:', error);
|
||||
throw new Error('获取订单统计失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new OrderService();
|
||||
Reference in New Issue
Block a user