修改后端接口
This commit is contained in:
@@ -46,7 +46,7 @@ const getEmployees = async (req, res) => {
|
||||
where,
|
||||
limit,
|
||||
offset,
|
||||
order: [['createdAt', 'DESC']],
|
||||
order: [['created_at', 'DESC']],
|
||||
attributes: {
|
||||
exclude: ['password'] // 不返回密码
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@ const getApplications = async (req, res) => {
|
||||
where.customer_phone = { [Op.like]: `%${searchValue}%` };
|
||||
} else if (searchField === 'customerIdCard') {
|
||||
where.customer_id_card = { [Op.like]: `%${searchValue}%` };
|
||||
} else if (searchField === 'applicationNumber') {
|
||||
// 数据库中实际没有applicationNumber字段,使用id作为替代
|
||||
where.id = { [Op.like]: `%${searchValue}%` };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +50,17 @@ const getApplications = async (req, res) => {
|
||||
const offset = (parseInt(page) - 1) * parseInt(pageSize);
|
||||
const limit = parseInt(pageSize);
|
||||
|
||||
// 排序参数
|
||||
const order = [[sortField, sortOrder.toUpperCase()]];
|
||||
// 排序参数 - 映射字段名
|
||||
const fieldMapping = {
|
||||
'createdAt': 'created_at',
|
||||
'updatedAt': 'updated_at',
|
||||
'applicationDate': 'application_date',
|
||||
'loanAmount': 'loan_amount',
|
||||
'loanTerm': 'loan_term',
|
||||
'interestRate': 'interest_rate'
|
||||
};
|
||||
const dbSortField = fieldMapping[sortField] || sortField;
|
||||
const order = [[dbSortField, sortOrder.toUpperCase()]];
|
||||
|
||||
// 查询数据
|
||||
const { count, rows } = await LoanApplication.findAndCountAll({
|
||||
|
||||
@@ -37,6 +37,9 @@ const getContracts = async (req, res) => {
|
||||
where.customer_phone = { [Op.like]: `%${searchValue}%` };
|
||||
} else if (searchField === 'customerIdCard') {
|
||||
where.customer_id_card = { [Op.like]: `%${searchValue}%` };
|
||||
} else if (searchField === 'applicationNumber') {
|
||||
// 数据库中实际没有applicationNumber字段,使用id作为替代
|
||||
where.id = { [Op.like]: `%${searchValue}%` };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +52,17 @@ const getContracts = async (req, res) => {
|
||||
const offset = (parseInt(page) - 1) * parseInt(pageSize);
|
||||
const limit = parseInt(pageSize);
|
||||
|
||||
// 排序参数
|
||||
const order = [[sortField, sortOrder.toUpperCase()]];
|
||||
// 排序参数 - 映射字段名
|
||||
const fieldMapping = {
|
||||
'createdAt': 'created_at',
|
||||
'updatedAt': 'updated_at',
|
||||
'contractDate': 'contract_date',
|
||||
'loanAmount': 'loan_amount',
|
||||
'loanTerm': 'loan_term',
|
||||
'interestRate': 'interest_rate'
|
||||
};
|
||||
const dbSortField = fieldMapping[sortField] || sortField;
|
||||
const order = [[dbSortField, sortOrder.toUpperCase()]];
|
||||
|
||||
// 查询数据
|
||||
const { count, rows } = await LoanContract.findAndCountAll({
|
||||
|
||||
@@ -200,6 +200,14 @@ const createLoanProduct = async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
// 检查用户信息
|
||||
if (!req.user || !req.user.id) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '用户信息无效'
|
||||
});
|
||||
}
|
||||
|
||||
const product = await LoanProduct.create({
|
||||
productName,
|
||||
loanAmount,
|
||||
|
||||
@@ -68,21 +68,14 @@ module.exports = (sequelize) => {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
comment: '锁定到期时间'
|
||||
},
|
||||
createdBy: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '创建人ID'
|
||||
},
|
||||
updatedBy: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '更新人ID'
|
||||
}
|
||||
}, {
|
||||
tableName: 'bank_employees',
|
||||
timestamps: true,
|
||||
createdAt: 'created_at',
|
||||
updatedAt: 'updated_at',
|
||||
paranoid: true,
|
||||
deletedAt: 'deleted_at',
|
||||
comment: '银行员工表',
|
||||
hooks: {
|
||||
beforeSave: async (employee) => {
|
||||
|
||||
@@ -107,7 +107,11 @@ Role.init({
|
||||
}, {
|
||||
sequelize,
|
||||
tableName: 'bank_roles',
|
||||
modelName: 'Role'
|
||||
modelName: 'Role',
|
||||
timestamps: true,
|
||||
underscored: true,
|
||||
createdAt: 'created_at',
|
||||
updatedAt: 'updated_at'
|
||||
});
|
||||
|
||||
module.exports = Role;
|
||||
42
bank-backend/test-create-loan-product.js
Normal file
42
bank-backend/test-create-loan-product.js
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 测试创建贷款商品
|
||||
*/
|
||||
const { LoanProduct } = require('./models');
|
||||
|
||||
async function testCreateLoanProduct() {
|
||||
try {
|
||||
console.log('🧪 测试创建贷款商品...');
|
||||
|
||||
const productData = {
|
||||
productName: '测试贷款产品',
|
||||
loanAmount: '50000~5000000',
|
||||
loanTerm: 12,
|
||||
interestRate: 5.5,
|
||||
serviceArea: '北京市',
|
||||
servicePhone: '13800138000',
|
||||
productDescription: '这是一个测试贷款产品',
|
||||
applicationRequirements: '需要提供身份证和收入证明',
|
||||
requiredDocuments: '身份证、收入证明、银行流水',
|
||||
approvalProcess: '提交申请->审核->放款',
|
||||
riskLevel: 'LOW',
|
||||
minLoanAmount: 50000,
|
||||
maxLoanAmount: 5000000,
|
||||
createdBy: 2,
|
||||
updatedBy: 2
|
||||
};
|
||||
|
||||
console.log('创建数据:', productData);
|
||||
|
||||
const product = await LoanProduct.create(productData);
|
||||
|
||||
console.log('✅ 创建成功:', product.toJSON());
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 创建失败:', error.message);
|
||||
console.error('详细错误:', error);
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
testCreateLoanProduct();
|
||||
@@ -1,16 +0,0 @@
|
||||
const axios = require('axios');
|
||||
|
||||
async function testLogin() {
|
||||
try {
|
||||
console.log('测试登录API...');
|
||||
const response = await axios.post('http://localhost:3001/api/auth/login', {
|
||||
username: 'admin',
|
||||
password: 'Admin123456'
|
||||
});
|
||||
console.log('登录成功:', response.data);
|
||||
} catch (error) {
|
||||
console.log('登录失败:', error.response ? error.response.data : error.message);
|
||||
}
|
||||
}
|
||||
|
||||
testLogin();
|
||||
@@ -79,6 +79,154 @@
|
||||
</a-table>
|
||||
</div>
|
||||
|
||||
<!-- 新增对话框 -->
|
||||
<a-modal
|
||||
v-model:open="addModalVisible"
|
||||
title="新增贷款商品"
|
||||
width="800px"
|
||||
:confirm-loading="addLoading"
|
||||
@ok="handleAddSubmit"
|
||||
@cancel="handleAddCancel"
|
||||
>
|
||||
<a-form
|
||||
ref="addFormRef"
|
||||
:model="addForm"
|
||||
:rules="addFormRules"
|
||||
layout="vertical"
|
||||
v-if="addModalVisible"
|
||||
>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="贷款产品名称" name="productName">
|
||||
<a-input v-model:value="addForm.productName" placeholder="请输入贷款产品名称" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="贷款额度" name="loanAmount">
|
||||
<a-input
|
||||
v-model:value="addForm.loanAmount"
|
||||
placeholder="请输入贷款额度,如:50000~5000000"
|
||||
style="width: 100%"
|
||||
addon-after="元"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="贷款周期" name="loanTerm">
|
||||
<a-input-number
|
||||
v-model:value="addForm.loanTerm"
|
||||
placeholder="请输入贷款周期"
|
||||
:min="1"
|
||||
style="width: 100%"
|
||||
addon-after="个月"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="贷款利率" name="interestRate">
|
||||
<a-input
|
||||
v-model:value="addForm.interestRate"
|
||||
placeholder="请输入贷款利率,如:3.90"
|
||||
style="width: 100%"
|
||||
addon-after="%"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="服务区域" name="serviceArea">
|
||||
<a-input v-model:value="addForm.serviceArea" placeholder="请输入服务区域" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="服务电话" name="servicePhone">
|
||||
<a-input v-model:value="addForm.servicePhone" placeholder="请输入服务电话" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="最小贷款金额" name="minLoanAmount">
|
||||
<a-input-number
|
||||
v-model:value="addForm.minLoanAmount"
|
||||
placeholder="请输入最小贷款金额"
|
||||
:min="0"
|
||||
style="width: 100%"
|
||||
addon-after="元"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="最大贷款金额" name="maxLoanAmount">
|
||||
<a-input-number
|
||||
v-model:value="addForm.maxLoanAmount"
|
||||
placeholder="请输入最大贷款金额"
|
||||
:min="0"
|
||||
style="width: 100%"
|
||||
addon-after="元"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="风险等级" name="riskLevel">
|
||||
<a-select v-model:value="addForm.riskLevel" placeholder="请选择风险等级">
|
||||
<a-select-option value="LOW">低风险</a-select-option>
|
||||
<a-select-option value="MEDIUM">中风险</a-select-option>
|
||||
<a-select-option value="HIGH">高风险</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item label="在售状态" name="onSaleStatus">
|
||||
<a-switch v-model:checked="addForm.onSaleStatus" />
|
||||
<span style="margin-left: 8px">{{ addForm.onSaleStatus ? '在售' : '停售' }}</span>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item label="产品描述" name="productDescription">
|
||||
<a-textarea
|
||||
v-model:value="addForm.productDescription"
|
||||
placeholder="请输入产品描述"
|
||||
:rows="3"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="申请要求" name="applicationRequirements">
|
||||
<a-textarea
|
||||
v-model:value="addForm.applicationRequirements"
|
||||
placeholder="请输入申请要求"
|
||||
:rows="3"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="所需材料" name="requiredDocuments">
|
||||
<a-textarea
|
||||
v-model:value="addForm.requiredDocuments"
|
||||
placeholder="请输入所需材料"
|
||||
:rows="3"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="审批流程" name="approvalProcess">
|
||||
<a-textarea
|
||||
v-model:value="addForm.approvalProcess"
|
||||
placeholder="请输入审批流程"
|
||||
:rows="3"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
|
||||
<!-- 编辑对话框 -->
|
||||
<a-modal
|
||||
v-model:open="editModalVisible"
|
||||
@@ -229,6 +377,27 @@ const loading = ref(false)
|
||||
const searchText = ref('')
|
||||
const products = ref([])
|
||||
|
||||
// 新增相关
|
||||
const addModalVisible = ref(false)
|
||||
const addLoading = ref(false)
|
||||
const addFormRef = ref(null)
|
||||
const addForm = reactive({
|
||||
productName: '',
|
||||
loanAmount: '',
|
||||
loanTerm: null,
|
||||
interestRate: '',
|
||||
serviceArea: '',
|
||||
servicePhone: '',
|
||||
minLoanAmount: null,
|
||||
maxLoanAmount: null,
|
||||
riskLevel: 'LOW',
|
||||
onSaleStatus: true,
|
||||
productDescription: '',
|
||||
applicationRequirements: '',
|
||||
requiredDocuments: '',
|
||||
approvalProcess: ''
|
||||
})
|
||||
|
||||
// 编辑相关
|
||||
const editModalVisible = ref(false)
|
||||
const editLoading = ref(false)
|
||||
@@ -314,6 +483,78 @@ const editFormRules = {
|
||||
]
|
||||
}
|
||||
|
||||
// 新增表单验证规则
|
||||
const addFormRules = {
|
||||
productName: [
|
||||
{ required: true, message: '请输入贷款产品名称', trigger: 'blur' },
|
||||
{ min: 2, max: 50, message: '产品名称长度在2-50个字符', trigger: 'blur' }
|
||||
],
|
||||
loanAmount: [
|
||||
{ required: true, message: '请输入贷款额度', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
if (!value) return Promise.reject('请输入贷款额度')
|
||||
// 支持数字或范围字符串(如:50000~5000000)
|
||||
if (typeof value === 'number') {
|
||||
if (value <= 0) return Promise.reject('贷款额度必须大于0')
|
||||
} else if (typeof value === 'string') {
|
||||
// 处理范围字符串
|
||||
if (value.includes('~')) {
|
||||
const [min, max] = value.split('~').map(v => parseFloat(v.trim()))
|
||||
if (isNaN(min) || isNaN(max) || min <= 0 || max <= 0) {
|
||||
return Promise.reject('贷款额度范围格式不正确')
|
||||
}
|
||||
} else {
|
||||
const numValue = parseFloat(value)
|
||||
if (isNaN(numValue) || numValue <= 0) {
|
||||
return Promise.reject('贷款额度必须大于0')
|
||||
}
|
||||
}
|
||||
}
|
||||
return Promise.resolve()
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
loanTerm: [
|
||||
{ required: true, message: '请输入贷款周期', trigger: 'blur' },
|
||||
{ type: 'number', min: 1, message: '贷款周期必须大于0', trigger: 'blur' }
|
||||
],
|
||||
interestRate: [
|
||||
{ required: true, message: '请输入贷款利率', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
if (!value) return Promise.reject('请输入贷款利率')
|
||||
const numValue = parseFloat(value)
|
||||
if (isNaN(numValue)) return Promise.reject('请输入有效的数字')
|
||||
if (numValue < 0 || numValue > 100) {
|
||||
return Promise.reject('贷款利率必须在0-100之间')
|
||||
}
|
||||
return Promise.resolve()
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
serviceArea: [
|
||||
{ required: true, message: '请输入服务区域', trigger: 'blur' }
|
||||
],
|
||||
servicePhone: [
|
||||
{ required: true, message: '请输入服务电话', trigger: 'blur' },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
|
||||
],
|
||||
minLoanAmount: [
|
||||
{ required: true, message: '请输入最小贷款金额', trigger: 'blur' },
|
||||
{ type: 'number', min: 0, message: '最小贷款金额不能小于0', trigger: 'blur' }
|
||||
],
|
||||
maxLoanAmount: [
|
||||
{ required: true, message: '请输入最大贷款金额', trigger: 'blur' },
|
||||
{ type: 'number', min: 0, message: '最大贷款金额不能小于0', trigger: 'blur' }
|
||||
],
|
||||
riskLevel: [
|
||||
{ required: true, message: '请选择风险等级', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
|
||||
// 行选择配置
|
||||
const rowSelection = {
|
||||
selectedRowKeys: selectedRowKeys,
|
||||
@@ -472,7 +713,24 @@ const handleReset = () => {
|
||||
}
|
||||
|
||||
const handleAddProduct = () => {
|
||||
message.info('新增贷款功能开发中...')
|
||||
// 重置表单
|
||||
Object.assign(addForm, {
|
||||
productName: '',
|
||||
loanAmount: '',
|
||||
loanTerm: null,
|
||||
interestRate: '',
|
||||
serviceArea: '',
|
||||
servicePhone: '',
|
||||
minLoanAmount: null,
|
||||
maxLoanAmount: null,
|
||||
riskLevel: 'LOW',
|
||||
onSaleStatus: true,
|
||||
productDescription: '',
|
||||
applicationRequirements: '',
|
||||
requiredDocuments: '',
|
||||
approvalProcess: ''
|
||||
})
|
||||
addModalVisible.value = true
|
||||
}
|
||||
|
||||
const handleEdit = async (record) => {
|
||||
@@ -554,6 +812,36 @@ const handleEditCancel = () => {
|
||||
editFormRef.value?.resetFields()
|
||||
}
|
||||
|
||||
// 新增提交
|
||||
const handleAddSubmit = async () => {
|
||||
try {
|
||||
await addFormRef.value.validate()
|
||||
addLoading.value = true
|
||||
|
||||
const response = await api.loanProducts.create(addForm)
|
||||
|
||||
if (response.success) {
|
||||
message.success('新增贷款商品成功')
|
||||
addModalVisible.value = false
|
||||
addFormRef.value?.resetFields()
|
||||
fetchProducts() // 刷新列表
|
||||
} else {
|
||||
message.error(response.message || '新增失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('新增失败:', error)
|
||||
message.error('新增失败')
|
||||
} finally {
|
||||
addLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 新增取消
|
||||
const handleAddCancel = () => {
|
||||
addModalVisible.value = false
|
||||
addFormRef.value?.resetFields()
|
||||
}
|
||||
|
||||
// 删除产品
|
||||
const handleDelete = async (record) => {
|
||||
try {
|
||||
|
||||
25
government-admin/package-lock.json
generated
25
government-admin/package-lock.json
generated
@@ -10,7 +10,6 @@
|
||||
"dependencies": {
|
||||
"@ant-design/icons-vue": "^6.1.0",
|
||||
"ant-design-vue": "^4.0.0",
|
||||
"axios": "^1.4.0",
|
||||
"dayjs": "^1.11.18",
|
||||
"echarts": "^5.4.2",
|
||||
"pinia": "^2.1.6",
|
||||
@@ -20,6 +19,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"axios": "^1.12.2",
|
||||
"eslint": "^8.45.0",
|
||||
"eslint-plugin-vue": "^9.15.1",
|
||||
"sass": "^1.93.0",
|
||||
@@ -1238,12 +1238,14 @@
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.12.2.tgz",
|
||||
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
@@ -1294,6 +1296,7 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -1370,6 +1373,7 @@
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
@@ -1471,6 +1475,7 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
@@ -1519,6 +1524,7 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
@@ -1555,6 +1561,7 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -1564,6 +1571,7 @@
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -1573,6 +1581,7 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
@@ -1585,6 +1594,7 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -1928,6 +1938,7 @@
|
||||
"version": "1.15.11",
|
||||
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -1948,6 +1959,7 @@
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
@@ -1986,6 +1998,7 @@
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -1995,6 +2008,7 @@
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
@@ -2019,6 +2033,7 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
@@ -2083,6 +2098,7 @@
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -2112,6 +2128,7 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -2124,6 +2141,7 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
@@ -2139,6 +2157,7 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
@@ -2394,6 +2413,7 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -2418,6 +2438,7 @@
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
@@ -2427,6 +2448,7 @@
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
@@ -2708,6 +2730,7 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
"dependencies": {
|
||||
"@ant-design/icons-vue": "^6.1.0",
|
||||
"ant-design-vue": "^4.0.0",
|
||||
"axios": "^1.4.0",
|
||||
"dayjs": "^1.11.18",
|
||||
"echarts": "^5.4.2",
|
||||
"pinia": "^2.1.6",
|
||||
@@ -22,6 +21,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"axios": "^1.12.2",
|
||||
"eslint": "^8.45.0",
|
||||
"eslint-plugin-vue": "^9.15.1",
|
||||
"sass": "^1.93.0",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { message } from 'antd'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import axios from 'axios'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
// 创建axios实例
|
||||
const instance = axios.create({
|
||||
@@ -11,14 +10,14 @@ const instance = axios.create({
|
||||
}
|
||||
})
|
||||
|
||||
// 请求拦截器
|
||||
// 请求拦截器 - 从localStorage中获取token
|
||||
instance.interceptors.request.use(
|
||||
config => {
|
||||
// 获取用户store
|
||||
const userStore = useUserStore()
|
||||
// 从localStorage中获取token
|
||||
const token = localStorage.getItem('token')
|
||||
// 如果有token,添加到请求头
|
||||
if (userStore.token) {
|
||||
config.headers['Authorization'] = `Bearer ${userStore.token}`
|
||||
if (token) {
|
||||
config.headers['Authorization'] = `Bearer ${token}`
|
||||
}
|
||||
return config
|
||||
},
|
||||
@@ -40,227 +39,257 @@ instance.interceptors.response.use(
|
||||
switch (error.response.status) {
|
||||
case 401:
|
||||
// 未授权,跳转到登录页面
|
||||
const userStore = useUserStore()
|
||||
userStore.logout()
|
||||
localStorage.removeItem('token')
|
||||
window.location.href = '/login'
|
||||
import('ant-design-vue').then(({ message }) => {
|
||||
message.error('登录已过期,请重新登录')
|
||||
})
|
||||
message.error('登录已过期,请重新登录')
|
||||
break
|
||||
case 403:
|
||||
import('ant-design-vue').then(({ message }) => {
|
||||
message.error('没有权限执行此操作')
|
||||
})
|
||||
message.error('没有权限执行此操作')
|
||||
break
|
||||
case 404:
|
||||
import('ant-design-vue').then(({ message }) => {
|
||||
message.error('请求的资源不存在')
|
||||
})
|
||||
message.error('请求的资源不存在')
|
||||
break
|
||||
case 500:
|
||||
import('ant-design-vue').then(({ message }) => {
|
||||
message.error('服务器内部错误')
|
||||
})
|
||||
message.error('服务器内部错误')
|
||||
break
|
||||
default:
|
||||
import('ant-design-vue').then(({ message }) => {
|
||||
message.error(error.response.data.message || '请求失败')
|
||||
})
|
||||
message.error('请求失败')
|
||||
}
|
||||
} else if (error.request) {
|
||||
// 请求发出但没有收到响应
|
||||
import('ant-design-vue').then(({ message }) => {
|
||||
message.error('网络错误,请检查网络连接')
|
||||
})
|
||||
message.error('网络连接失败')
|
||||
} else {
|
||||
// 请求配置出错
|
||||
import('ant-design-vue').then(({ message }) => {
|
||||
message.error('请求配置错误')
|
||||
})
|
||||
message.error('请求配置出错')
|
||||
}
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// API接口定义
|
||||
const api = {
|
||||
// 认证相关API
|
||||
auth: {
|
||||
// 登录
|
||||
login: (data) => instance.post('/auth/login', data),
|
||||
// 获取用户信息
|
||||
getUserInfo: () => instance.get('/auth/userinfo'),
|
||||
// 退出登录
|
||||
logout: () => instance.post('/auth/logout'),
|
||||
// 认证相关的API
|
||||
const auth = {
|
||||
// 登录
|
||||
login: data => instance.post('/auth/login', data),
|
||||
// 获取用户信息
|
||||
getUserInfo: () => instance.get('/auth/userInfo'),
|
||||
// 退出登录
|
||||
logout: () => instance.post('/auth/logout'),
|
||||
// 重置密码
|
||||
resetPassword: data => instance.post('/auth/resetPassword', data)
|
||||
}
|
||||
|
||||
// 用户管理相关的API
|
||||
const user = {
|
||||
// 获取用户列表
|
||||
getList: params => instance.get('/user/list', { params }),
|
||||
// 新增用户
|
||||
create: data => instance.post('/user/create', data),
|
||||
// 编辑用户
|
||||
update: data => instance.post('/user/update', data),
|
||||
// 删除用户
|
||||
delete: id => instance.post(`/user/delete/${id}`),
|
||||
// 禁用/启用用户
|
||||
toggleStatus: data => instance.post('/user/toggleStatus', data),
|
||||
// 重置密码
|
||||
resetPassword: id => instance.post(`/user/resetPassword/${id}`)
|
||||
}
|
||||
|
||||
// 监管相关的API
|
||||
const supervision = {
|
||||
// 获取监管列表
|
||||
getList: params => instance.get('/supervision/list', { params }),
|
||||
// 获取监管详情
|
||||
getDetail: id => instance.get(`/supervision/detail/${id}`),
|
||||
// 新增监管
|
||||
create: data => instance.post('/supervision/create', data),
|
||||
// 更新监管
|
||||
update: data => instance.post('/supervision/update', data),
|
||||
// 删除监管
|
||||
delete: id => instance.post(`/supervision/delete/${id}`)
|
||||
}
|
||||
|
||||
// 审批相关的API
|
||||
const approval = {
|
||||
// 获取审批列表
|
||||
getList: params => instance.get('/approval/list', { params }),
|
||||
// 获取审批详情
|
||||
getDetail: id => instance.get(`/approval/detail/${id}`),
|
||||
// 提交审批
|
||||
submit: data => instance.post('/approval/submit', data),
|
||||
// 审批操作
|
||||
approve: data => instance.post('/approval/approve', data),
|
||||
// 驳回操作
|
||||
reject: data => instance.post('/approval/reject', data),
|
||||
// 撤回操作
|
||||
withdraw: id => instance.post(`/approval/withdraw/${id}`)
|
||||
}
|
||||
|
||||
// 疫情监控相关的API
|
||||
const epidemic = {
|
||||
// 获取疫情监控列表
|
||||
getList: params => instance.get('/epidemic/list', { params }),
|
||||
// 获取疫情监控详情
|
||||
getDetail: id => instance.get(`/epidemic/detail/${id}`),
|
||||
// 新增疫情监控
|
||||
create: data => instance.post('/epidemic/create', data),
|
||||
// 更新疫情监控
|
||||
update: data => instance.post('/epidemic/update', data),
|
||||
// 删除疫情监控
|
||||
delete: id => instance.post(`/epidemic/delete/${id}`),
|
||||
// 处理疫情
|
||||
handle: data => instance.post('/epidemic/handle', data)
|
||||
}
|
||||
|
||||
// 数据可视化相关的API
|
||||
const visualization = {
|
||||
// 获取养殖情况统计
|
||||
getBreedingStats: params => instance.get('/visualization/breedingStats', { params }),
|
||||
// 获取疫情趋势
|
||||
getEpidemicTrend: params => instance.get('/visualization/epidemicTrend', { params }),
|
||||
// 获取监管效果
|
||||
getSupervisionEffect: params => instance.get('/visualization/supervisionEffect', { params })
|
||||
}
|
||||
|
||||
// 文件管理相关的API
|
||||
const file = {
|
||||
// 上传文件
|
||||
upload: data => instance.post('/file/upload', data),
|
||||
// 下载文件
|
||||
download: id => instance.get(`/file/download/${id}`),
|
||||
// 获取文件列表
|
||||
getList: params => instance.get('/file/list', { params }),
|
||||
// 删除文件
|
||||
delete: id => instance.post(`/file/delete/${id}`)
|
||||
}
|
||||
|
||||
// 人员管理相关的API
|
||||
const staff = {
|
||||
// 获取人员列表
|
||||
getList: params => instance.get('/staff/list', { params }),
|
||||
// 新增人员
|
||||
create: data => instance.post('/staff/create', data),
|
||||
// 更新人员
|
||||
update: data => instance.post('/staff/update', data),
|
||||
// 删除人员
|
||||
delete: id => instance.post(`/staff/delete/${id}`),
|
||||
// 获取人员详情
|
||||
getDetail: id => instance.get(`/staff/detail/${id}`)
|
||||
}
|
||||
|
||||
// 服务管理相关的API
|
||||
const service = {
|
||||
// 获取服务列表
|
||||
getList: params => instance.get('/service/list', { params }),
|
||||
// 新增服务
|
||||
create: data => instance.post('/service/create', data),
|
||||
// 更新服务
|
||||
update: data => instance.post('/service/update', data),
|
||||
// 删除服务
|
||||
delete: id => instance.post(`/service/delete/${id}`),
|
||||
// 获取服务详情
|
||||
getDetail: id => instance.get(`/service/detail/${id}`)
|
||||
}
|
||||
|
||||
// 仓库管理相关的API
|
||||
const warehouse = {
|
||||
// 获取仓库列表
|
||||
getList: params => instance.get('/warehouse/list', { params }),
|
||||
// 新增仓库
|
||||
create: data => instance.post('/warehouse/create', data),
|
||||
// 更新仓库
|
||||
update: data => instance.post('/warehouse/update', data),
|
||||
// 删除仓库
|
||||
delete: id => instance.post(`/warehouse/delete/${id}`),
|
||||
// 获取仓库详情
|
||||
getDetail: id => instance.get(`/warehouse/detail/${id}`)
|
||||
}
|
||||
|
||||
// 系统设置相关的API
|
||||
const system = {
|
||||
// 获取系统设置
|
||||
getSettings: () => instance.get('/system/settings'),
|
||||
// 更新系统设置
|
||||
updateSettings: data => instance.post('/system/updateSettings', data),
|
||||
// 获取操作日志
|
||||
getOperationLogs: params => instance.get('/system/operationLogs', { params })
|
||||
}
|
||||
|
||||
// 政府管理相关的API
|
||||
const government = {
|
||||
// 行政人员管理
|
||||
adminStaff: {
|
||||
// 获取行政人员列表
|
||||
getList: params => instance.get('/government/admin-staff/list', { params }),
|
||||
// 新增行政人员
|
||||
create: data => instance.post('/government/admin-staff/create', data),
|
||||
// 编辑行政人员
|
||||
update: data => instance.post('/government/admin-staff/update', data),
|
||||
// 删除行政人员
|
||||
delete: id => instance.post(`/government/admin-staff/delete/${id}`),
|
||||
// 重置密码
|
||||
resetPassword: (data) => instance.post('/auth/reset-password', data)
|
||||
resetPassword: id => instance.post(`/government/admin-staff/reset-password/${id}`)
|
||||
},
|
||||
|
||||
// 用户管理相关API
|
||||
user: {
|
||||
// 获取用户列表
|
||||
getList: (params) => instance.get('/users', { params }),
|
||||
// 获取单个用户信息
|
||||
getDetail: (id) => instance.get(`/users/${id}`),
|
||||
// 创建用户
|
||||
create: (data) => instance.post('/users', data),
|
||||
// 更新用户
|
||||
update: (id, data) => instance.put(`/users/${id}`, data),
|
||||
// 删除用户
|
||||
delete: (id) => instance.delete(`/users/${id}`),
|
||||
// 批量删除用户
|
||||
batchDelete: (ids) => instance.post('/users/batch-delete', { ids }),
|
||||
// 更新用户状态
|
||||
updateStatus: (id, status) => instance.put(`/users/${id}/status`, { status })
|
||||
// 部门管理
|
||||
departments: {
|
||||
// 获取部门列表
|
||||
getList: () => instance.get('/government/departments/list'),
|
||||
// 新增部门
|
||||
create: data => instance.post('/government/departments/create', data),
|
||||
// 编辑部门
|
||||
update: data => instance.post('/government/departments/update', data),
|
||||
// 删除部门
|
||||
delete: id => instance.post(`/government/departments/delete/${id}`)
|
||||
},
|
||||
|
||||
// 监管相关API
|
||||
supervision: {
|
||||
// 获取监管统计数据
|
||||
getStats: () => instance.get('/supervision/stats'),
|
||||
// 获取监管任务列表
|
||||
getTasks: (params) => instance.get('/supervision/tasks', { params }),
|
||||
// 获取监管任务详情
|
||||
getTaskDetail: (id) => instance.get(`/supervision/tasks/${id}`),
|
||||
// 创建监管任务
|
||||
createTask: (data) => instance.post('/supervision/tasks', data),
|
||||
// 更新监管任务
|
||||
updateTask: (id, data) => instance.put(`/supervision/tasks/${id}`, data),
|
||||
// 删除监管任务
|
||||
deleteTask: (id) => instance.delete(`/supervision/tasks/${id}`)
|
||||
// 岗位管理
|
||||
positions: {
|
||||
// 获取岗位列表
|
||||
getList: () => instance.get('/government/positions/list'),
|
||||
// 新增岗位
|
||||
create: data => instance.post('/government/positions/create', data),
|
||||
// 编辑岗位
|
||||
update: data => instance.post('/government/positions/update', data),
|
||||
// 删除岗位
|
||||
delete: id => instance.post(`/government/positions/delete/${id}`)
|
||||
},
|
||||
|
||||
// 审批相关API
|
||||
approval: {
|
||||
// 获取审批流程列表
|
||||
getList: (params) => instance.get('/approval', { params }),
|
||||
// 创建审批流程
|
||||
create: (data) => instance.post('/approval', data),
|
||||
// 获取审批详情
|
||||
getDetail: (id) => instance.get(`/approval/${id}`),
|
||||
// 更新审批状态
|
||||
updateStatus: (id, status) => instance.put(`/approval/${id}/status`, { status })
|
||||
},
|
||||
|
||||
// 疫情监控相关API
|
||||
epidemic: {
|
||||
// 获取疫情统计数据
|
||||
getStats: () => instance.get('/epidemic/stats'),
|
||||
// 获取疫苗接种数据
|
||||
getVaccinationData: (params) => instance.get('/epidemic/vaccination', { params }),
|
||||
// 获取检测数据
|
||||
getTestData: (params) => instance.get('/epidemic/test', { params })
|
||||
},
|
||||
|
||||
// 数据可视化相关API
|
||||
visualization: {
|
||||
// 获取可视化数据
|
||||
getData: (params) => instance.get('/visualization/data', { params })
|
||||
},
|
||||
|
||||
// 文件管理相关API
|
||||
file: {
|
||||
// 获取文件列表
|
||||
getList: (params) => instance.get('/files', { params }),
|
||||
// 上传文件
|
||||
upload: (file, onUploadProgress) => {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return instance.post('/files/upload', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
},
|
||||
onUploadProgress
|
||||
})
|
||||
// 养殖户管理
|
||||
farmers: {
|
||||
// 获取养殖户列表
|
||||
getList: params => instance.get('/government/farmers', { params }),
|
||||
// 新增养殖户
|
||||
create: data => instance.post('/government/farmers', data),
|
||||
// 编辑养殖户
|
||||
update: (id, data) => instance.put(`/government/farmers/${id}`, data),
|
||||
// 删除养殖户
|
||||
delete: id => instance.delete(`/government/farmers/${id}`),
|
||||
// 重置密码
|
||||
resetPassword: id => instance.post(`/government/farmers/${id}/reset-password`)
|
||||
},
|
||||
// 下载文件
|
||||
download: (id) => instance.get(`/files/${id}/download`, { responseType: 'blob' }),
|
||||
// 删除文件
|
||||
delete: (id) => instance.delete(`/files/${id}`)
|
||||
// 养殖类型相关
|
||||
farmTypes: {
|
||||
// 获取养殖类型列表
|
||||
getList: () => instance.get('/government/farm-types')
|
||||
},
|
||||
|
||||
// 人员管理相关API
|
||||
personnel: {
|
||||
// 获取人员列表
|
||||
getList: (params) => instance.get('/personnel', { params }),
|
||||
// 创建人员
|
||||
create: (data) => instance.post('/personnel', data),
|
||||
// 更新人员
|
||||
update: (id, data) => instance.put(`/personnel/${id}`, data),
|
||||
// 删除人员
|
||||
delete: (id) => instance.delete(`/personnel/${id}`)
|
||||
},
|
||||
|
||||
// 服务管理相关API
|
||||
service: {
|
||||
// 获取服务列表
|
||||
getList: (params) => instance.get('/service', { params }),
|
||||
// 创建服务
|
||||
create: (data) => instance.post('/service', data),
|
||||
// 更新服务
|
||||
update: (id, data) => instance.put(`/service/${id}`, data),
|
||||
// 删除服务
|
||||
delete: (id) => instance.delete(`/service/${id}`)
|
||||
},
|
||||
|
||||
// 仓库管理相关API
|
||||
warehouse: {
|
||||
// 获取物资列表
|
||||
getList: (params) => instance.get('/warehouse', { params }),
|
||||
// 获取单个物资详情
|
||||
getDetail: (id) => instance.get(`/warehouse/${id}`),
|
||||
// 创建物资
|
||||
create: (data) => instance.post('/warehouse', data),
|
||||
// 更新物资
|
||||
update: (id, data) => instance.put(`/warehouse/${id}`, data),
|
||||
// 删除物资
|
||||
delete: (id) => instance.delete(`/warehouse/${id}`),
|
||||
// 物资入库
|
||||
stockIn: (data) => instance.post('/warehouse/in', data),
|
||||
// 物资出库
|
||||
stockOut: (data) => instance.post('/warehouse/out', data),
|
||||
// 获取库存统计信息
|
||||
getStats: () => instance.get('/warehouse/stats')
|
||||
},
|
||||
|
||||
// 系统设置相关API
|
||||
system: {
|
||||
// 获取系统设置
|
||||
getSettings: () => instance.get('/system/settings'),
|
||||
// 更新系统设置
|
||||
updateSettings: (data) => instance.put('/system/settings', data),
|
||||
// 获取日志列表
|
||||
getLogs: (params) => instance.get('/system/logs', { params })
|
||||
},
|
||||
|
||||
// 政府管理相关API
|
||||
government: {
|
||||
// 行政人员管理
|
||||
adminStaff: {
|
||||
// 获取行政人员列表
|
||||
getList: (params) => instance.get('/government/admin-staff', { params }),
|
||||
// 创建行政人员
|
||||
create: (data) => instance.post('/government/admin-staff', data),
|
||||
// 更新行政人员
|
||||
update: (id, data) => instance.put(`/government/admin-staff/${id}`, data),
|
||||
// 删除行政人员
|
||||
delete: (id) => instance.delete(`/government/admin-staff/${id}`),
|
||||
// 重置行政人员密码
|
||||
resetPassword: (id) => instance.post(`/government/admin-staff/${id}/reset-password`)
|
||||
},
|
||||
|
||||
// 部门管理
|
||||
departments: {
|
||||
// 获取部门列表
|
||||
getList: (params) => instance.get('/government/departments', { params })
|
||||
},
|
||||
|
||||
// 岗位管理
|
||||
positions: {
|
||||
// 获取岗位列表
|
||||
getList: (params) => instance.get('/government/positions', { params })
|
||||
}
|
||||
// 养殖种类相关
|
||||
animalTypes: {
|
||||
// 获取养殖种类列表
|
||||
getList: () => instance.get('/government/animal-types')
|
||||
}
|
||||
}
|
||||
|
||||
// 导出所有API
|
||||
const api = {
|
||||
auth,
|
||||
user,
|
||||
supervision,
|
||||
approval,
|
||||
epidemic,
|
||||
visualization,
|
||||
file,
|
||||
staff,
|
||||
service,
|
||||
warehouse,
|
||||
system,
|
||||
government
|
||||
}
|
||||
|
||||
export default api
|
||||
@@ -166,16 +166,32 @@ const fetchAdminStaffList = async () => {
|
||||
search: searchValue.value
|
||||
}
|
||||
const response = await api.government.adminStaff.getList(params)
|
||||
staffData.value = response.data.map(item => ({
|
||||
...item,
|
||||
department: departments.value.find(dept => dept.id === item.department_id)?.name || '',
|
||||
position: positions.value.find(pos => pos.id === item.position_id)?.name || '',
|
||||
key: item.id
|
||||
}))
|
||||
pagination.total = response.total
|
||||
|
||||
// 确保response.data是一个数组
|
||||
if (response && Array.isArray(response.data)) {
|
||||
staffData.value = response.data.map(item => ({
|
||||
...item,
|
||||
department: departments.value.find(dept => dept.id === item.department_id)?.name || '',
|
||||
position: positions.value.find(pos => pos.id === item.position_id)?.name || '',
|
||||
key: item.id
|
||||
}))
|
||||
pagination.total = response.total || response.data.length
|
||||
} else {
|
||||
// 处理异常情况
|
||||
staffData.value = []
|
||||
pagination.total = 0
|
||||
console.error('行政人员列表数据格式错误:', response)
|
||||
}
|
||||
|
||||
console.log('行政人员列表数据:', staffData.value)
|
||||
} catch (error) {
|
||||
message.error('获取行政人员列表失败')
|
||||
console.error('获取行政人员列表失败:', error)
|
||||
// 添加错误详细信息展示
|
||||
if (error.response) {
|
||||
console.error('错误状态码:', error.response.status)
|
||||
console.error('错误数据:', error.response.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +199,16 @@ const fetchAdminStaffList = async () => {
|
||||
const fetchDepartments = async () => {
|
||||
try {
|
||||
const response = await api.government.departments.getList()
|
||||
departments.value = response.data
|
||||
// 处理数据格式 - 确保departments是一个数组
|
||||
if (response && response.data && Array.isArray(response.data)) {
|
||||
departments.value = response.data
|
||||
} else if (response) {
|
||||
// 处理API返回的非标准格式数据
|
||||
departments.value = Object.values(response).map(item =>
|
||||
typeof item === 'object' ? item : { id: item, name: item }
|
||||
)
|
||||
}
|
||||
console.log('部门列表数据:', departments.value)
|
||||
} catch (error) {
|
||||
message.error('获取部门列表失败')
|
||||
console.error('获取部门列表失败:', error)
|
||||
@@ -194,7 +219,16 @@ const fetchDepartments = async () => {
|
||||
const fetchPositions = async () => {
|
||||
try {
|
||||
const response = await api.government.positions.getList()
|
||||
positions.value = response.data
|
||||
// 处理数据格式 - 确保positions是一个数组
|
||||
if (response && response.data && Array.isArray(response.data)) {
|
||||
positions.value = response.data
|
||||
} else if (response) {
|
||||
// 处理API返回的非标准格式数据
|
||||
positions.value = Object.values(response).map(item =>
|
||||
typeof item === 'object' ? item : { id: item, name: item }
|
||||
)
|
||||
}
|
||||
console.log('岗位列表数据:', positions.value)
|
||||
} catch (error) {
|
||||
message.error('获取岗位列表失败')
|
||||
console.error('获取岗位列表失败:', error)
|
||||
|
||||
@@ -7,20 +7,28 @@
|
||||
</div>
|
||||
<div>
|
||||
<a-input-search
|
||||
placeholder="请输入"
|
||||
placeholder="请输入账号、姓名、养殖场名称"
|
||||
style="width: 200px; margin-right: 8px;"
|
||||
v-model:value="searchKeyword"
|
||||
@search="handleSearch"
|
||||
/>
|
||||
<a-select
|
||||
placeholder="账号"
|
||||
style="width: 120px;"
|
||||
v-model:value="accountFilter"
|
||||
placeholder="养殖场类型"
|
||||
style="width: 120px; margin-right: 8px;"
|
||||
v-model:value="farmTypeFilter"
|
||||
@change="handleSearch"
|
||||
>
|
||||
<a-select-option value="">全部</a-select-option>
|
||||
<a-select-option value="account1">账号筛选1</a-select-option>
|
||||
<a-select-option value="account2">账号筛选2</a-select-option>
|
||||
<a-select-option v-for="type in farmTypes" :key="type.value" :value="type.value">{{ type.label }}</a-select-option>
|
||||
</a-select>
|
||||
<a-select
|
||||
placeholder="养殖种类"
|
||||
style="width: 120px;"
|
||||
v-model:value="animalTypeFilter"
|
||||
@change="handleSearch"
|
||||
>
|
||||
<a-select-option value="">全部</a-select-option>
|
||||
<a-select-option v-for="type in animalTypes" :key="type.value" :value="type.value">{{ type.label }}</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -32,11 +40,13 @@
|
||||
:pagination="pagination"
|
||||
row-key="id"
|
||||
:scroll="{ x: 'max-content' }"
|
||||
@change="handleTableChange"
|
||||
:loading="loading"
|
||||
>
|
||||
<!-- 状态列 -->
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'status'">
|
||||
<a-tag :color="getStatusColor(record.status)">{{ getStatusText(record.status) }}</a-tag>
|
||||
<a-tag :color="getStatusColor(record.status_value)">{{ record.status }}</a-tag>
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<div style="display: flex; gap: 8px;">
|
||||
@@ -48,16 +58,91 @@
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<!-- 新增/编辑养殖户对话框 -->
|
||||
<a-modal
|
||||
v-model:visible="modalVisible"
|
||||
:title="modalTitle"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-form :model="formData" :label-col="{ span: 6 }" :wrapper-col="{ span: 16 }">
|
||||
<a-form-item label="账号" name="account" :rules="[{ required: true, message: '请输入账号' }]">
|
||||
<a-input v-model:value="formData.account" placeholder="请输入账号" />
|
||||
</a-form-item>
|
||||
<a-form-item label="账号昵称" name="nickname" :rules="[{ required: true, message: '请输入账号昵称' }]">
|
||||
<a-input v-model:value="formData.nickname" placeholder="请输入账号昵称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="真实姓名" name="real_name" :rules="[{ required: true, message: '请输入真实姓名' }]">
|
||||
<a-input v-model:value="formData.real_name" placeholder="请输入真实姓名" />
|
||||
</a-form-item>
|
||||
<a-form-item label="养殖场名称" name="farm_name" :rules="[{ required: true, message: '请输入养殖场名称' }]">
|
||||
<a-input v-model:value="formData.farm_name" placeholder="请输入养殖场名称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="养殖场类型" name="farm_type" :rules="[{ required: true, message: '请选择养殖场类型' }]">
|
||||
<a-select v-model:value="formData.farm_type" placeholder="请选择养殖场类型">
|
||||
<a-select-option v-for="type in farmTypes" :key="type.value" :value="type.value">{{ type.label }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="养殖种类" name="animal_type" :rules="[{ required: true, message: '请选择养殖种类' }]">
|
||||
<a-select v-model:value="formData.animal_type" placeholder="请选择养殖种类">
|
||||
<a-select-option v-for="type in animalTypes" :key="type.value" :value="type.value">{{ type.label }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="养殖数量" name="animal_count" :rules="[{ required: true, message: '请输入养殖数量' }, { type: 'number', min: 0 }]">
|
||||
<a-input-number v-model:value="formData.animal_count" :min="0" placeholder="请输入养殖数量" />
|
||||
</a-form-item>
|
||||
<a-form-item label="养殖场地址" name="address" :rules="[{ required: true, message: '请输入养殖场地址' }]">
|
||||
<a-input v-model:value="formData.address" placeholder="请输入养殖场地址" />
|
||||
</a-form-item>
|
||||
<a-form-item label="状态" name="status" :rules="[{ required: true, message: '请选择状态' }]">
|
||||
<a-select v-model:value="formData.status" placeholder="请选择状态">
|
||||
<a-select-option value="active">正常</a-select-option>
|
||||
<a-select-option value="inactive">暂停</a-select-option>
|
||||
<a-select-option value="closed">关闭</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
|
||||
<!-- 查看详情对话框 -->
|
||||
<a-modal
|
||||
v-model:visible="viewModalVisible"
|
||||
title="养殖户详情"
|
||||
@cancel="handleViewCancel"
|
||||
>
|
||||
<div v-if="selectedFarmer">
|
||||
<p><strong>账号:</strong>{{ selectedFarmer.account }}</p>
|
||||
<p><strong>账号昵称:</strong>{{ selectedFarmer.nickname }}</p>
|
||||
<p><strong>真实姓名:</strong>{{ selectedFarmer.real_name }}</p>
|
||||
<p><strong>养殖场名称:</strong>{{ selectedFarmer.farm_name }}</p>
|
||||
<p><strong>养殖场类型:</strong>{{ selectedFarmer.farm_type }}</p>
|
||||
<p><strong>养殖种类:</strong>{{ selectedFarmer.animal_type }}</p>
|
||||
<p><strong>养殖数量:</strong>{{ selectedFarmer.animal_count }}</p>
|
||||
<p><strong>养殖场地址:</strong>{{ selectedFarmer.address }}</p>
|
||||
<p><strong>登记时间:</strong>{{ selectedFarmer.register_time }}</p>
|
||||
<p><strong>登记人:</strong>{{ selectedFarmer.registrar }}</p>
|
||||
<p><strong>状态:</strong><a-tag :color="getStatusColor(selectedFarmer.status_value)">{{ selectedFarmer.status }}</a-tag></p>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { message, Modal } from 'ant-design-vue'
|
||||
import api from '@/utils/api'
|
||||
|
||||
// 搜索关键词
|
||||
// 搜索条件
|
||||
const searchKeyword = ref('')
|
||||
const accountFilter = ref('')
|
||||
const farmTypeFilter = ref('')
|
||||
const animalTypeFilter = ref('')
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(false)
|
||||
|
||||
// 养殖类型和种类列表
|
||||
const farmTypes = ref([])
|
||||
const animalTypes = ref([])
|
||||
|
||||
// 表格列定义
|
||||
const columns = [
|
||||
@@ -67,12 +152,6 @@ const columns = [
|
||||
key: 'account',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '机构识别码',
|
||||
dataIndex: 'orgCode',
|
||||
key: 'orgCode',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '账号昵称',
|
||||
dataIndex: 'nickname',
|
||||
@@ -81,32 +160,32 @@ const columns = [
|
||||
},
|
||||
{
|
||||
title: '真实姓名',
|
||||
dataIndex: 'realName',
|
||||
key: 'realName',
|
||||
dataIndex: 'real_name',
|
||||
key: 'real_name',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '养殖场名称',
|
||||
dataIndex: 'farmName',
|
||||
key: 'farmName',
|
||||
dataIndex: 'farm_name',
|
||||
key: 'farm_name',
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
title: '养殖场类型',
|
||||
dataIndex: 'farmType',
|
||||
key: 'farmType',
|
||||
dataIndex: 'farm_type',
|
||||
key: 'farm_type',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '养殖场种类',
|
||||
dataIndex: 'animalType',
|
||||
key: 'animalType',
|
||||
title: '养殖种类',
|
||||
dataIndex: 'animal_type',
|
||||
key: 'animal_type',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '数量',
|
||||
dataIndex: 'animalCount',
|
||||
key: 'animalCount',
|
||||
dataIndex: 'animal_count',
|
||||
key: 'animal_count',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
@@ -117,10 +196,10 @@ const columns = [
|
||||
},
|
||||
{
|
||||
title: '登记时间',
|
||||
dataIndex: 'registerTime',
|
||||
key: 'registerTime',
|
||||
dataIndex: 'register_time',
|
||||
key: 'register_time',
|
||||
width: 150,
|
||||
sorter: (a, b) => new Date(a.registerTime) - new Date(b.registerTime)
|
||||
sorter: (a, b) => new Date(a.register_time) - new Date(b.register_time)
|
||||
},
|
||||
{
|
||||
title: '登记人',
|
||||
@@ -129,11 +208,9 @@ const columns = [
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
dataIndex: 'updateTime',
|
||||
key: 'updateTime',
|
||||
width: 150,
|
||||
sorter: (a, b) => new Date(a.updateTime) - new Date(b.updateTime)
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
@@ -149,127 +226,206 @@ const pagination = reactive({
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showTotal: (total) => `共 ${total} 条记录`
|
||||
showTotal: (total) => `共 ${total} 条记录`,
|
||||
pageSizeOptions: ['10', '20', '50', '100']
|
||||
})
|
||||
|
||||
// 模拟数据
|
||||
const farmersData = ref([
|
||||
{
|
||||
id: '1',
|
||||
account: '176****4187',
|
||||
orgCode: '18094-785778',
|
||||
nickname: '齐五旺',
|
||||
realName: '齐五旺',
|
||||
farmName: '齐五旺养殖场',
|
||||
farmType: '散养',
|
||||
animalType: '牛',
|
||||
animalCount: 10,
|
||||
address: '内蒙古自治区通辽市扎鲁特旗鲁北镇额尔格图木塔格镇',
|
||||
registerTime: '2023-05-22 08:59:44',
|
||||
registrar: '齐五旺',
|
||||
updateTime: '2025-08-10 06:07:41',
|
||||
status: 'active'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
account: '132****9345',
|
||||
orgCode: '384708-449642',
|
||||
nickname: '扎鲁特数据中心',
|
||||
realName: '扎鲁特数据中心',
|
||||
farmName: '扎鲁特数据中心',
|
||||
farmType: '散养',
|
||||
animalType: '牛',
|
||||
animalCount: 10,
|
||||
address: '内蒙古自治区通辽市扎鲁特旗',
|
||||
registerTime: '2024-07-23 13:37:00',
|
||||
registrar: '扎鲁特数据中心',
|
||||
updateTime: '2024-10-16 11:33:02',
|
||||
status: 'active'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
account: '139****1221',
|
||||
orgCode: '382987-319364',
|
||||
nickname: '邵晓艳',
|
||||
realName: '邵晓艳',
|
||||
farmName: '扎鲁特旗百顺养殖专业合作社',
|
||||
farmType: '规模',
|
||||
animalType: '牛',
|
||||
animalCount: 741,
|
||||
address: '内蒙古自治区通辽市扎鲁特旗巴日合镇巴日合村委会',
|
||||
registerTime: '2023-07-10 11:17:50',
|
||||
registrar: '赵忠林',
|
||||
updateTime: '2024-07-03 11:53:47',
|
||||
status: 'active'
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
account: '151****1013',
|
||||
orgCode: '1069-899484',
|
||||
nickname: '双成家庭农场',
|
||||
realName: '双成',
|
||||
farmName: '双成家庭农场',
|
||||
farmType: '散养',
|
||||
animalType: '牛',
|
||||
animalCount: 74,
|
||||
address: '内蒙古自治区通辽市扎鲁特旗鲁北镇宝力根花镇',
|
||||
registerTime: '2023-04-24 10:54:22',
|
||||
registrar: '双成',
|
||||
updateTime: '2024-05-08 11:14:48',
|
||||
status: 'active'
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
account: '150****1368',
|
||||
orgCode: '1451-668414',
|
||||
nickname: '刘超',
|
||||
realName: '刘超',
|
||||
farmName: '大数据中心',
|
||||
farmType: '散养',
|
||||
animalType: '牛',
|
||||
animalCount: 11,
|
||||
address: '内蒙古自治区通辽市扎鲁特旗鲁北镇',
|
||||
registerTime: '2023-04-11 15:36:37',
|
||||
registrar: '孙主任',
|
||||
updateTime: '2024-03-04 11:18:24',
|
||||
status: 'active'
|
||||
}
|
||||
])
|
||||
// 养殖户数据
|
||||
const farmersData = ref([])
|
||||
|
||||
// 对话框相关
|
||||
const modalVisible = ref(false)
|
||||
const modalTitle = ref('')
|
||||
const editingId = ref(null)
|
||||
const formData = reactive({
|
||||
account: '',
|
||||
nickname: '',
|
||||
real_name: '',
|
||||
farm_name: '',
|
||||
farm_type: '',
|
||||
animal_type: '',
|
||||
animal_count: 0,
|
||||
address: '',
|
||||
status: 'active'
|
||||
})
|
||||
|
||||
// 查看详情相关
|
||||
const viewModalVisible = ref(false)
|
||||
const selectedFarmer = ref(null)
|
||||
|
||||
// 初始化数据
|
||||
onMounted(() => {
|
||||
pagination.total = farmersData.value.length
|
||||
initData()
|
||||
})
|
||||
|
||||
// 初始化数据
|
||||
const initData = async () => {
|
||||
try {
|
||||
await Promise.all([
|
||||
fetchFarmers(),
|
||||
fetchFarmTypes(),
|
||||
fetchAnimalTypes()
|
||||
])
|
||||
} catch (error) {
|
||||
message.error('初始化数据失败')
|
||||
console.error('初始化数据失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取养殖户列表
|
||||
const fetchFarmers = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const params = {
|
||||
page: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
search: searchKeyword.value,
|
||||
farmType: farmTypeFilter.value,
|
||||
animalType: animalTypeFilter.value
|
||||
}
|
||||
|
||||
const response = await api.government.farmers.getList(params)
|
||||
farmersData.value = response.data || []
|
||||
pagination.total = response.total || 0
|
||||
} catch (error) {
|
||||
message.error('获取养殖户列表失败')
|
||||
console.error('获取养殖户列表失败:', error)
|
||||
farmersData.value = []
|
||||
pagination.total = 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取养殖类型列表
|
||||
const fetchFarmTypes = async () => {
|
||||
try {
|
||||
const response = await api.government.farmTypes.getList()
|
||||
farmTypes.value = response
|
||||
} catch (error) {
|
||||
message.error('获取养殖类型列表失败')
|
||||
console.error('获取养殖类型列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取养殖种类列表
|
||||
const fetchAnimalTypes = async () => {
|
||||
try {
|
||||
const response = await api.government.animalTypes.getList()
|
||||
animalTypes.value = response
|
||||
} catch (error) {
|
||||
message.error('获取养殖种类列表失败')
|
||||
console.error('获取养殖种类列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理搜索
|
||||
const handleSearch = () => {
|
||||
// 实际应用中这里应该调用API进行搜索
|
||||
message.success('搜索条件已应用')
|
||||
pagination.current = 1
|
||||
fetchFarmers()
|
||||
}
|
||||
|
||||
// 处理表格分页、排序等变化
|
||||
const handleTableChange = (paginationInfo) => {
|
||||
pagination.current = paginationInfo.current
|
||||
pagination.pageSize = paginationInfo.pageSize
|
||||
fetchFarmers()
|
||||
}
|
||||
|
||||
// 处理导出
|
||||
const handleExport = () => {
|
||||
message.success('数据导出中...')
|
||||
// 实际应用中这里应该调用导出API
|
||||
}
|
||||
|
||||
// 处理添加养殖户
|
||||
const handleAddFarmer = () => {
|
||||
message.success('打开新增养殖监管表单')
|
||||
modalTitle.value = '新增养殖户'
|
||||
editingId.value = null
|
||||
// 重置表单
|
||||
Object.keys(formData).forEach(key => {
|
||||
formData[key] = key === 'animal_count' ? 0 : key === 'status' ? 'active' : ''
|
||||
})
|
||||
modalVisible.value = true
|
||||
}
|
||||
|
||||
// 处理编辑养殖户
|
||||
const handleEdit = async (record) => {
|
||||
try {
|
||||
modalTitle.value = '编辑养殖户'
|
||||
editingId.value = record.id
|
||||
// 填充表单数据
|
||||
formData.account = record.account
|
||||
formData.nickname = record.nickname
|
||||
formData.real_name = record.real_name
|
||||
formData.farm_name = record.farm_name
|
||||
formData.farm_type = record.farm_type
|
||||
formData.animal_type = record.animal_type
|
||||
formData.animal_count = record.animal_count
|
||||
formData.address = record.address
|
||||
formData.status = record.status_value
|
||||
modalVisible.value = true
|
||||
} catch (error) {
|
||||
message.error('加载养殖户信息失败')
|
||||
console.error('加载养殖户信息失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理查看详情
|
||||
const handleView = (record) => {
|
||||
message.info(`查看养殖户: ${record.farmName}`)
|
||||
selectedFarmer.value = record
|
||||
viewModalVisible.value = true
|
||||
}
|
||||
|
||||
// 处理编辑
|
||||
const handleEdit = (record) => {
|
||||
message.info(`编辑养殖户: ${record.farmName}`)
|
||||
}
|
||||
|
||||
// 处理删除
|
||||
// 处理删除养殖户
|
||||
const handleDelete = (id) => {
|
||||
message.success(`删除养殖户ID: ${id}`)
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '确定要删除该养殖户吗?',
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
async onOk() {
|
||||
try {
|
||||
await api.government.farmers.delete(id)
|
||||
message.success('删除成功')
|
||||
fetchFarmers()
|
||||
} catch (error) {
|
||||
message.error('删除失败')
|
||||
console.error('删除养殖户失败:', error)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 处理对话框确定
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
if (editingId.value) {
|
||||
// 编辑养殖户
|
||||
await api.government.farmers.update(editingId.value, formData)
|
||||
message.success('更新成功')
|
||||
} else {
|
||||
// 新增养殖户
|
||||
await api.government.farmers.create(formData)
|
||||
message.success('创建成功')
|
||||
}
|
||||
modalVisible.value = false
|
||||
fetchFarmers()
|
||||
} catch (error) {
|
||||
message.error(editingId.value ? '更新失败' : '创建失败')
|
||||
console.error(editingId.value ? '更新养殖户失败:' : '创建养殖户失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理对话框取消
|
||||
const handleCancel = () => {
|
||||
modalVisible.value = false
|
||||
}
|
||||
|
||||
// 处理查看详情对话框取消
|
||||
const handleViewCancel = () => {
|
||||
viewModalVisible.value = false
|
||||
selectedFarmer.value = null
|
||||
}
|
||||
|
||||
// 获取状态颜色
|
||||
|
||||
65
government-admin/test-admin-staff-api.mjs
Normal file
65
government-admin/test-admin-staff-api.mjs
Normal file
@@ -0,0 +1,65 @@
|
||||
// 测试行政人员管理API接口
|
||||
import axios from 'axios';
|
||||
|
||||
// 创建axios实例
|
||||
const instance = axios.create({
|
||||
baseURL: 'http://localhost:5352/api',
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
// 登录获取token
|
||||
const login = async () => {
|
||||
try {
|
||||
const response = await instance.post('/auth/login', {
|
||||
username: 'admin',
|
||||
password: '123456'
|
||||
});
|
||||
console.log('登录成功,获取到token');
|
||||
return response.data.token;
|
||||
} catch (error) {
|
||||
console.error('登录失败:', error.message);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// 测试获取行政人员列表
|
||||
const testGetAdminStaffList = async (token) => {
|
||||
try {
|
||||
instance.defaults.headers.common['Authorization'] = `Bearer ${token}`;
|
||||
const response = await instance.get('/personnel');
|
||||
console.log('\n获取行政人员列表成功:');
|
||||
console.log('- 状态码:', response.status);
|
||||
console.log('- 返回数据结构:', Object.keys(response.data));
|
||||
console.log('- 行政人员总数:', response.data.total);
|
||||
console.log('- 返回的行政人员列表长度:', response.data.data.length);
|
||||
if (response.data.data.length > 0) {
|
||||
console.log('- 第一条行政人员数据:', response.data.data[0]);
|
||||
}
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('获取行政人员列表失败:', error.message);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// 主测试函数
|
||||
const runTests = async () => {
|
||||
console.log('开始测试行政人员管理API...');
|
||||
try {
|
||||
// 1. 登录获取token
|
||||
const token = await login();
|
||||
|
||||
// 2. 测试获取行政人员列表
|
||||
await testGetAdminStaffList(token);
|
||||
|
||||
console.log('\n所有测试完成!');
|
||||
} catch (error) {
|
||||
console.error('测试失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 运行测试
|
||||
runTests();
|
||||
152
government-admin/test-admin-staff-component.mjs
Normal file
152
government-admin/test-admin-staff-component.mjs
Normal file
@@ -0,0 +1,152 @@
|
||||
// 前端组件API测试脚本 - ES模块格式
|
||||
import axios from 'axios';
|
||||
|
||||
// 创建axios实例
|
||||
const instance = axios.create({
|
||||
baseURL: 'http://localhost:5352/api',
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
// 登录获取token
|
||||
async function login() {
|
||||
try {
|
||||
const response = await instance.post('/auth/login', {
|
||||
username: 'admin',
|
||||
password: '123456'
|
||||
});
|
||||
console.log('登录成功:', response.data);
|
||||
// 修正token获取路径 - 正确路径是response.data.data.token
|
||||
return response.data.data?.token || null;
|
||||
} catch (error) {
|
||||
console.error('登录失败:', error);
|
||||
console.error('错误详情:', error.response?.data || error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试获取行政人员列表
|
||||
async function testGetAdminStaffList(token) {
|
||||
try {
|
||||
const response = await instance.get('/personnel', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
params: {
|
||||
page: 1,
|
||||
pageSize: 10
|
||||
}
|
||||
});
|
||||
console.log('行政人员列表获取成功:');
|
||||
console.log('- 数据结构:', Object.keys(response.data));
|
||||
console.log('- 行政人员总数:', response.data.total);
|
||||
console.log('- 行政人员列表数据长度:', response.data.data?.length || 0);
|
||||
if (response.data.data && response.data.data.length > 0) {
|
||||
console.log('- 第一条数据示例:', response.data.data[0]);
|
||||
}
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('行政人员列表获取失败:', error);
|
||||
console.error('错误详情:', error.response?.data || error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试获取部门列表
|
||||
async function testGetDepartmentsList(token) {
|
||||
try {
|
||||
const response = await instance.get('/government/departments', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
console.log('部门列表获取成功:');
|
||||
console.log('- 数据结构:', Object.keys(response.data));
|
||||
console.log('- 部门列表数据长度:', response.data.data?.length || 0);
|
||||
if (response.data.data && response.data.data.length > 0) {
|
||||
console.log('- 第一条数据示例:', response.data.data[0]);
|
||||
}
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('部门列表获取失败:', error);
|
||||
console.error('错误详情:', error.response?.data || error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 测试获取岗位列表
|
||||
async function testGetPositionsList(token) {
|
||||
try {
|
||||
const response = await instance.get('/government/positions', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
console.log('岗位列表获取成功:');
|
||||
console.log('- 数据结构:', Object.keys(response.data));
|
||||
console.log('- 岗位列表数据长度:', response.data.data?.length || 0);
|
||||
if (response.data.data && response.data.data.length > 0) {
|
||||
console.log('- 第一条数据示例:', response.data.data[0]);
|
||||
}
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('岗位列表获取失败:', error);
|
||||
console.error('错误详情:', error.response?.data || error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 主测试函数 - 模拟AdminStaff组件的初始化流程
|
||||
async function runComponentTest() {
|
||||
console.log('开始模拟AdminStaff组件初始化测试...');
|
||||
|
||||
// 1. 登录获取token
|
||||
console.log('\n1. 登录认证');
|
||||
const token = await login();
|
||||
if (!token) {
|
||||
console.error('测试失败: 无法获取登录token');
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 测试获取部门列表 - 对应组件中的fetchDepartments()
|
||||
console.log('\n2. 获取部门列表');
|
||||
const departmentsData = await testGetDepartmentsList(token);
|
||||
|
||||
// 3. 测试获取岗位列表 - 对应组件中的fetchPositions()
|
||||
console.log('\n3. 获取岗位列表');
|
||||
const positionsData = await testGetPositionsList(token);
|
||||
|
||||
// 4. 测试获取行政人员列表 - 对应组件中的fetchAdminStaffList()
|
||||
console.log('\n4. 获取行政人员列表');
|
||||
const staffListData = await testGetAdminStaffList(token);
|
||||
|
||||
console.log('\n测试完成!');
|
||||
console.log('----------------------------------------');
|
||||
console.log('测试结果总结:');
|
||||
console.log('- 登录:', token ? '成功' : '失败');
|
||||
console.log('- 部门列表:', departmentsData ? '成功' : '失败');
|
||||
console.log('- 岗位列表:', positionsData ? '成功' : '失败');
|
||||
console.log('- 行政人员列表:', staffListData ? '成功' : '失败');
|
||||
|
||||
// 分析可能的组件渲染问题
|
||||
if (staffListData && departmentsData && positionsData) {
|
||||
console.log('\n所有API调用成功,但页面仍显示空白可能的原因:');
|
||||
console.log('1. 数据格式不匹配 - 检查返回数据结构是否与组件期望的一致');
|
||||
console.log('2. 组件生命周期问题 - 检查onMounted中是否正确调用initData()');
|
||||
console.log('3. 数据处理逻辑错误 - 检查staffData.value的赋值和转换逻辑');
|
||||
console.log('4. 权限问题 - 检查用户角色和权限是否正确');
|
||||
console.log('5. 前端控制台错误 - 检查浏览器控制台是否有详细错误信息');
|
||||
} else {
|
||||
console.log('\nAPI调用失败是页面空白的可能原因,请检查:');
|
||||
console.log('1. 后端接口是否正确实现');
|
||||
console.log('2. 认证token是否有效');
|
||||
console.log('3. 网络连接是否正常');
|
||||
}
|
||||
}
|
||||
|
||||
// 运行测试
|
||||
runComponentTest().catch(err => {
|
||||
console.error('测试过程中发生错误:', err);
|
||||
});
|
||||
@@ -23,8 +23,17 @@ const accessLogStream = fs.createWriteStream(
|
||||
);
|
||||
app.use(morgan('combined', { stream: accessLogStream }));
|
||||
|
||||
// 数据库连接(暂时注释掉,使用内存数据)
|
||||
// const sequelize = require('./config/database');
|
||||
// 数据库连接
|
||||
const sequelize = require('./config/database');
|
||||
|
||||
// 测试数据库连接
|
||||
sequelize.authenticate()
|
||||
.then(() => {
|
||||
console.log('数据库连接成功');
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('数据库连接失败:', err);
|
||||
});
|
||||
|
||||
// 路由
|
||||
app.use('/api/auth', require('./routes/auth'));
|
||||
@@ -58,5 +67,4 @@ app.use((err, req, res, next) => {
|
||||
const PORT = process.env.PORT || 5352;
|
||||
app.listen(PORT, () => {
|
||||
console.log(`政府管理系统后端服务已启动,端口: ${PORT}`);
|
||||
console.log(`使用内存数据,无需数据库连接`);
|
||||
});
|
||||
@@ -1,14 +1,14 @@
|
||||
require('dotenv').config();
|
||||
const { Sequelize } = require('sequelize');
|
||||
const config = require('./index.js');
|
||||
|
||||
const sequelize = new Sequelize(
|
||||
process.env.DB_NAME,
|
||||
process.env.DB_USER,
|
||||
process.env.DB_PASSWORD,
|
||||
config.DB_CONFIG.database,
|
||||
config.DB_CONFIG.user,
|
||||
config.DB_CONFIG.password,
|
||||
{
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT,
|
||||
dialect: process.env.DB_DIALECT,
|
||||
host: config.DB_CONFIG.host,
|
||||
port: config.DB_CONFIG.port,
|
||||
dialect: config.DB_CONFIG.dialect,
|
||||
logging: process.env.NODE_ENV === 'development' ? console.log : false,
|
||||
pool: {
|
||||
max: 5,
|
||||
@@ -31,12 +31,14 @@ async function testConnection() {
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log('数据库连接成功');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('数据库连接失败:', error);
|
||||
process.exit(1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
testConnection();
|
||||
// 导出连接测试函数,但不自动执行
|
||||
module.exports.testConnection = testConnection;
|
||||
|
||||
module.exports = sequelize;
|
||||
@@ -1,11 +1,19 @@
|
||||
const DB_DIALECT = process.env.DB_DIALECT || 'mysql';
|
||||
const DB_HOST = process.env.DB_HOST || '129.211.213.226';
|
||||
const DB_PORT = process.env.DB_PORT || 9527;
|
||||
const DB_NAME = process.env.DB_NAME || 'ningxia_zhengfu';
|
||||
const DB_USER = process.env.DB_USER || 'root';
|
||||
const DB_PASSWORD = process.env.DB_PASSWORD || 'aiotAiot123!';
|
||||
|
||||
module.exports = {
|
||||
JWT_SECRET: 'your-secret-key-here', // 请在生产环境中替换为强密钥
|
||||
DB_CONFIG: {
|
||||
host: 'localhost',
|
||||
user: 'root',
|
||||
password: '',
|
||||
database: 'government_db',
|
||||
port: 3306
|
||||
host: DB_HOST,
|
||||
user: DB_USER,
|
||||
password: DB_PASSWORD,
|
||||
database: DB_NAME,
|
||||
port: DB_PORT,
|
||||
dialect: DB_DIALECT
|
||||
},
|
||||
PORT: 5352
|
||||
}
|
||||
@@ -1,51 +1,63 @@
|
||||
const jwt = require('jsonwebtoken')
|
||||
const jwt = require('jsonwebtoken');
|
||||
const User = require('../models/User');
|
||||
const AdminStaff = require('../models/AdminStaff');
|
||||
const bcrypt = require('bcryptjs');
|
||||
|
||||
// JWT配置
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-in-production'
|
||||
|
||||
// 临时用户数据(实际项目中应该从数据库获取)
|
||||
const users = [
|
||||
{
|
||||
id: 1,
|
||||
username: 'admin',
|
||||
password: '123456',
|
||||
name: '系统管理员',
|
||||
role: 'admin',
|
||||
email: 'admin@example.com'
|
||||
}
|
||||
]
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-in-production';
|
||||
|
||||
exports.login = async (req, res) => {
|
||||
try {
|
||||
const { username, password } = req.body
|
||||
const { username, password } = req.body;
|
||||
|
||||
// 查找用户
|
||||
const user = users.find(u => u.username === username && u.password === password)
|
||||
// 从数据库查找用户
|
||||
const user = await User.findOne({
|
||||
where: {
|
||||
username,
|
||||
status: 'active'
|
||||
}
|
||||
});
|
||||
|
||||
if (user) {
|
||||
const token = jwt.sign({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
role: user.role
|
||||
}, JWT_SECRET, { expiresIn: '2h' })
|
||||
|
||||
return res.json({
|
||||
code: 200,
|
||||
message: '登录成功',
|
||||
data: { token }
|
||||
})
|
||||
if (!user) {
|
||||
return res.status(401).json({
|
||||
code: 401,
|
||||
message: '用户名或密码错误'
|
||||
});
|
||||
}
|
||||
|
||||
res.status(401).json({
|
||||
code: 401,
|
||||
message: '用户名或密码错误'
|
||||
})
|
||||
// 验证密码
|
||||
const isPasswordValid = await bcrypt.compare(password, user.password);
|
||||
|
||||
if (!isPasswordValid) {
|
||||
return res.status(401).json({
|
||||
code: 401,
|
||||
message: '用户名或密码错误'
|
||||
});
|
||||
}
|
||||
|
||||
// 更新最后登录时间
|
||||
await user.update({
|
||||
last_login: new Date()
|
||||
});
|
||||
|
||||
const token = jwt.sign({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
role: user.role
|
||||
}, JWT_SECRET, { expiresIn: '2h' });
|
||||
|
||||
return res.json({
|
||||
code: 200,
|
||||
message: '登录成功',
|
||||
data: { token }
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('登录错误:', err);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器错误',
|
||||
error: err.message
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,51 +65,104 @@ exports.login = async (req, res) => {
|
||||
exports.getUserInfo = async (req, res) => {
|
||||
try {
|
||||
// 从token中解析用户信息
|
||||
const token = req.headers.authorization?.replace('Bearer ', '')
|
||||
const token = req.headers.authorization?.replace('Bearer ', '');
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
code: 401,
|
||||
message: '未提供认证令牌'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const decoded = jwt.verify(token, JWT_SECRET)
|
||||
const user = users.find(u => u.id === decoded.id)
|
||||
const decoded = jwt.verify(token, JWT_SECRET);
|
||||
|
||||
if (user) {
|
||||
const userInfo = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
name: user.name,
|
||||
role: user.role,
|
||||
avatar: '',
|
||||
email: user.email,
|
||||
permissions: ['dashboard', 'users', 'settings']
|
||||
}
|
||||
|
||||
return res.json({
|
||||
code: 200,
|
||||
message: '获取用户信息成功',
|
||||
data: userInfo
|
||||
})
|
||||
} else {
|
||||
// 从数据库获取用户信息
|
||||
const user = await User.findByPk(decoded.id, {
|
||||
include: [
|
||||
{
|
||||
model: AdminStaff,
|
||||
as: 'staffInfo'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
if (!user || user.status !== 'active') {
|
||||
return res.status(401).json({
|
||||
code: 401,
|
||||
message: '用户不存在'
|
||||
})
|
||||
message: '用户不存在或已禁用'
|
||||
});
|
||||
}
|
||||
|
||||
// 获取员工信息
|
||||
let staffInfo = null;
|
||||
try {
|
||||
staffInfo = await AdminStaff.findOne({
|
||||
where: {
|
||||
phone: user.username
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn('获取员工信息失败:', error);
|
||||
}
|
||||
|
||||
// 根据角色设置权限
|
||||
const permissions = getPermissionsByRole(user.role);
|
||||
|
||||
const userInfo = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
name: staffInfo?.name || user.username,
|
||||
role: user.role,
|
||||
avatar: '',
|
||||
email: '',
|
||||
phone: staffInfo?.phone || user.username,
|
||||
department: staffInfo?.department_id ? {
|
||||
id: staffInfo.department_id,
|
||||
name: ''
|
||||
} : null,
|
||||
position: staffInfo?.position_id ? {
|
||||
id: staffInfo.position_id,
|
||||
name: ''
|
||||
} : null,
|
||||
permissions
|
||||
};
|
||||
|
||||
return res.json({
|
||||
code: 200,
|
||||
message: '获取用户信息成功',
|
||||
data: userInfo
|
||||
});
|
||||
} catch (jwtError) {
|
||||
console.error('JWT验证错误:', jwtError);
|
||||
return res.status(401).json({
|
||||
code: 401,
|
||||
message: '认证令牌无效'
|
||||
})
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取用户信息错误:', err);
|
||||
res.status(500).json({
|
||||
code: 500,
|
||||
message: '服务器错误',
|
||||
error: err.message
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 根据角色获取权限
|
||||
exports.getPermissionsByRole = (role) => {
|
||||
const basePermissions = ['dashboard'];
|
||||
|
||||
switch (role) {
|
||||
case 'admin':
|
||||
return [...basePermissions, 'users', 'settings', 'supervision', 'approval', 'personnel', 'warehouse', 'epidemic', 'service', 'visualization'];
|
||||
case 'manager':
|
||||
return [...basePermissions, 'supervision', 'approval', 'personnel', 'warehouse', 'epidemic', 'service'];
|
||||
case 'inspector':
|
||||
return [...basePermissions, 'supervision', 'epidemic'];
|
||||
case 'clerk':
|
||||
return [...basePermissions, 'approval', 'personnel', 'warehouse', 'service'];
|
||||
default:
|
||||
return basePermissions;
|
||||
}
|
||||
};
|
||||
248
government-backend/controllers/farmerController.js
Normal file
248
government-backend/controllers/farmerController.js
Normal file
@@ -0,0 +1,248 @@
|
||||
const Farmer = require('../models/Farmer');
|
||||
const { Op } = require('sequelize');
|
||||
|
||||
// 获取养殖户列表
|
||||
const getFarmers = async (req, res) => {
|
||||
try {
|
||||
const { page = 1, pageSize = 10, search = '', farmType = '', animalType = '', status = '' } = req.query;
|
||||
|
||||
const whereCondition = {};
|
||||
|
||||
// 搜索条件
|
||||
if (search) {
|
||||
whereCondition[Op.or] = [
|
||||
{ nickname: { [Op.like]: `%${search}%` } },
|
||||
{ real_name: { [Op.like]: `%${search}%` } },
|
||||
{ farm_name: { [Op.like]: `%${search}%` } },
|
||||
{ account: { [Op.like]: `%${search}%` } }
|
||||
];
|
||||
}
|
||||
|
||||
// 养殖场类型筛选
|
||||
if (farmType) {
|
||||
whereCondition.farm_type = farmType;
|
||||
}
|
||||
|
||||
// 养殖种类筛选
|
||||
if (animalType) {
|
||||
whereCondition.animal_type = animalType;
|
||||
}
|
||||
|
||||
// 状态筛选
|
||||
if (status) {
|
||||
whereCondition.status = status;
|
||||
}
|
||||
|
||||
const offset = (page - 1) * pageSize;
|
||||
|
||||
const { count, rows } = await Farmer.findAndCountAll({
|
||||
where: whereCondition,
|
||||
offset,
|
||||
limit: parseInt(pageSize),
|
||||
order: [['register_time', 'DESC']]
|
||||
});
|
||||
|
||||
// 格式化数据以便前端使用
|
||||
const formattedData = rows.map(farmer => ({
|
||||
id: farmer.id,
|
||||
key: farmer.id.toString(),
|
||||
account: farmer.account,
|
||||
nickname: farmer.nickname,
|
||||
real_name: farmer.real_name,
|
||||
farm_name: farmer.farm_name,
|
||||
farm_type: farmer.farm_type,
|
||||
animal_type: farmer.animal_type,
|
||||
animal_count: farmer.animal_count,
|
||||
address: farmer.address,
|
||||
register_time: farmer.register_time.toLocaleString('zh-CN'),
|
||||
registrar: farmer.registrar,
|
||||
status: farmer.status === 'active' ? '正常' : farmer.status === 'inactive' ? '暂停' : '关闭',
|
||||
status_value: farmer.status
|
||||
}));
|
||||
|
||||
res.json({
|
||||
data: formattedData,
|
||||
total: count,
|
||||
page: parseInt(page),
|
||||
pageSize: parseInt(pageSize)
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('获取养殖户列表失败:', error);
|
||||
res.status(500).json({ message: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
// 新增养殖户
|
||||
const createFarmer = async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
account,
|
||||
nickname,
|
||||
real_name,
|
||||
farm_name,
|
||||
farm_type,
|
||||
animal_type,
|
||||
animal_count,
|
||||
address,
|
||||
status = 'active'
|
||||
} = req.body;
|
||||
|
||||
// 检查账号是否已存在
|
||||
const existingFarmer = await Farmer.findOne({ where: { account } });
|
||||
if (existingFarmer) {
|
||||
return res.status(400).json({ message: '该账号已存在' });
|
||||
}
|
||||
|
||||
const farmer = await Farmer.create({
|
||||
account,
|
||||
nickname,
|
||||
real_name,
|
||||
farm_name,
|
||||
farm_type,
|
||||
animal_type,
|
||||
animal_count,
|
||||
address,
|
||||
registrar: req.user?.username || 'system',
|
||||
status
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: '养殖户创建成功',
|
||||
data: farmer
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('创建养殖户失败:', error);
|
||||
res.status(500).json({ message: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
// 编辑养殖户
|
||||
const updateFarmer = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const {
|
||||
nickname,
|
||||
real_name,
|
||||
farm_name,
|
||||
farm_type,
|
||||
animal_type,
|
||||
animal_count,
|
||||
address,
|
||||
status
|
||||
} = req.body;
|
||||
|
||||
const farmer = await Farmer.findByPk(id);
|
||||
if (!farmer) {
|
||||
return res.status(404).json({ message: '养殖户不存在' });
|
||||
}
|
||||
|
||||
await farmer.update({
|
||||
nickname,
|
||||
real_name,
|
||||
farm_name,
|
||||
farm_type,
|
||||
animal_type,
|
||||
animal_count,
|
||||
address,
|
||||
status
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '养殖户信息更新成功',
|
||||
data: farmer
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新养殖户信息失败:', error);
|
||||
res.status(500).json({ message: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
// 删除养殖户
|
||||
const deleteFarmer = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const farmer = await Farmer.findByPk(id);
|
||||
if (!farmer) {
|
||||
return res.status(404).json({ message: '养殖户不存在' });
|
||||
}
|
||||
|
||||
await farmer.destroy();
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '养殖户删除成功'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('删除养殖户失败:', error);
|
||||
res.status(500).json({ message: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
// 重置养殖户密码(如果需要)
|
||||
const resetFarmerPassword = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const farmer = await Farmer.findByPk(id);
|
||||
if (!farmer) {
|
||||
return res.status(404).json({ message: '养殖户不存在' });
|
||||
}
|
||||
|
||||
// 在实际应用中,这里应该生成一个临时密码并发送给用户
|
||||
// 为了演示,我们只返回成功信息
|
||||
res.json({
|
||||
success: true,
|
||||
message: '密码重置成功,新密码已发送到用户手机'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('重置养殖户密码失败:', error);
|
||||
res.status(500).json({ message: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
// 获取养殖类型列表
|
||||
const getFarmTypes = async (req, res) => {
|
||||
try {
|
||||
const farmTypes = [
|
||||
{ value: '规模', label: '规模' },
|
||||
{ value: '散养', label: '散养' },
|
||||
{ value: '其他', label: '其他' }
|
||||
];
|
||||
|
||||
res.json(farmTypes);
|
||||
} catch (error) {
|
||||
console.error('获取养殖类型列表失败:', error);
|
||||
res.status(500).json({ message: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
// 获取养殖种类列表
|
||||
const getAnimalTypes = async (req, res) => {
|
||||
try {
|
||||
const animalTypes = [
|
||||
{ value: '牛', label: '牛' },
|
||||
{ value: '羊', label: '羊' },
|
||||
{ value: '猪', label: '猪' },
|
||||
{ value: '鸡', label: '鸡' },
|
||||
{ value: '其他', label: '其他' }
|
||||
];
|
||||
|
||||
res.json(animalTypes);
|
||||
} catch (error) {
|
||||
console.error('获取养殖种类列表失败:', error);
|
||||
res.status(500).json({ message: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getFarmers,
|
||||
createFarmer,
|
||||
updateFarmer,
|
||||
deleteFarmer,
|
||||
resetFarmerPassword,
|
||||
getFarmTypes,
|
||||
getAnimalTypes
|
||||
};
|
||||
113
government-backend/models/Farmer.js
Normal file
113
government-backend/models/Farmer.js
Normal file
@@ -0,0 +1,113 @@
|
||||
const sequelize = require('../config/database');
|
||||
const { DataTypes } = require('sequelize');
|
||||
|
||||
const Farmer = sequelize.define('Farmer', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true
|
||||
},
|
||||
account: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
comment: '账号'
|
||||
},
|
||||
org_code: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
comment: '机构识别码'
|
||||
},
|
||||
nickname: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
comment: '账号昵称'
|
||||
},
|
||||
real_name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
comment: '真实姓名'
|
||||
},
|
||||
farm_name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
comment: '养殖场名称'
|
||||
},
|
||||
farm_type: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
comment: '养殖场类型',
|
||||
validate: {
|
||||
isIn: [['规模', '散养', '其他']]
|
||||
}
|
||||
},
|
||||
animal_type: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
comment: '养殖场种类',
|
||||
validate: {
|
||||
isIn: [['牛', '羊', '猪', '鸡', '其他']]
|
||||
}
|
||||
},
|
||||
animal_count: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
comment: '养殖数量'
|
||||
},
|
||||
address: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
comment: '养殖场地址'
|
||||
},
|
||||
register_time: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '登记时间'
|
||||
},
|
||||
registrar: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
comment: '登记人'
|
||||
},
|
||||
update_time: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '更新时间'
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.ENUM('active', 'inactive', 'closed'),
|
||||
allowNull: false,
|
||||
defaultValue: 'active',
|
||||
comment: '状态:active-正常,inactive-暂停,closed-关闭'
|
||||
}
|
||||
}, {
|
||||
tableName: 'farmers',
|
||||
timestamps: true,
|
||||
createdAt: 'register_time',
|
||||
updatedAt: 'update_time',
|
||||
paranoid: false,
|
||||
indexes: [
|
||||
{
|
||||
name: 'idx_farmer_account',
|
||||
fields: ['account']
|
||||
},
|
||||
{
|
||||
name: 'idx_farmer_farm_name',
|
||||
fields: ['farm_name']
|
||||
},
|
||||
{
|
||||
name: 'idx_farmer_status',
|
||||
fields: ['status']
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 钩子函数,在保存前更新更新时间
|
||||
Farmer.beforeSave((farmer) => {
|
||||
farmer.update_time = new Date();
|
||||
});
|
||||
|
||||
module.exports = Farmer;
|
||||
59
government-backend/models/User.js
Normal file
59
government-backend/models/User.js
Normal file
@@ -0,0 +1,59 @@
|
||||
const sequelize = require('../config/database');
|
||||
const { DataTypes } = require('sequelize');
|
||||
|
||||
const User = sequelize.define('User', {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true
|
||||
},
|
||||
username: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
unique: true,
|
||||
comment: '用户名'
|
||||
},
|
||||
password: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
comment: '密码'
|
||||
},
|
||||
role: {
|
||||
type: DataTypes.ENUM('admin', 'manager', 'inspector', 'clerk'),
|
||||
allowNull: false,
|
||||
comment: '角色'
|
||||
},
|
||||
status: {
|
||||
type: DataTypes.ENUM('active', 'inactive'),
|
||||
allowNull: false,
|
||||
defaultValue: 'active',
|
||||
comment: '状态'
|
||||
},
|
||||
last_login: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
comment: '最后登录时间'
|
||||
}
|
||||
}, {
|
||||
tableName: 'users',
|
||||
timestamps: true,
|
||||
createdAt: 'created_at',
|
||||
updatedAt: 'updated_at',
|
||||
paranoid: false,
|
||||
indexes: [
|
||||
{
|
||||
name: 'idx_username',
|
||||
fields: ['username']
|
||||
},
|
||||
{
|
||||
name: 'idx_role',
|
||||
fields: ['role']
|
||||
},
|
||||
{
|
||||
name: 'idx_status',
|
||||
fields: ['status']
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
module.exports = User;
|
||||
120
government-backend/package-lock.json
generated
120
government-backend/package-lock.json
generated
@@ -20,6 +20,7 @@
|
||||
"sequelize": "^6.37.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^1.12.2",
|
||||
"nodemon": "^3.1.0"
|
||||
}
|
||||
},
|
||||
@@ -86,6 +87,13 @@
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/aws-ssl-profiles": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
|
||||
@@ -95,6 +103,18 @@
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.12.2.tgz",
|
||||
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.4",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
@@ -268,6 +288,19 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz",
|
||||
@@ -333,6 +366,16 @@
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/denque": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/denque/-/denque-2.1.0.tgz",
|
||||
@@ -447,6 +490,22 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz",
|
||||
@@ -539,6 +598,44 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.11",
|
||||
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz",
|
||||
@@ -674,6 +771,22 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
|
||||
@@ -1268,6 +1381,13 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pstree.remy": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmmirror.com/pstree.remy/-/pstree.remy-1.1.8.tgz",
|
||||
|
||||
@@ -8,19 +8,19 @@
|
||||
"dev": "nodemon app.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
"mysql2": "^3.6.5",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"body-parser": "^1.20.2",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.3.1",
|
||||
"body-parser": "^1.20.2",
|
||||
"express": "^4.18.2",
|
||||
"helmet": "^7.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"morgan": "^1.10.0",
|
||||
"sequelize": "^6.37.1",
|
||||
"mysql2": "^3.9.7"
|
||||
"mysql2": "^3.9.7",
|
||||
"sequelize": "^6.37.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^1.12.2",
|
||||
"nodemon": "^3.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const governmentController = require('../controllers/governmentController');
|
||||
const farmerController = require('../controllers/farmerController');
|
||||
|
||||
// 数据览仓接口
|
||||
router.get('/data-center', governmentController.getDataCenterStats);
|
||||
@@ -52,4 +53,26 @@ router.delete('/admin-staff/:id', governmentController.deleteAdminStaff);
|
||||
// 重置行政人员密码
|
||||
router.post('/admin-staff/:id/reset-password', governmentController.resetAdminStaffPassword);
|
||||
|
||||
// 养殖户管理接口
|
||||
// 获取养殖户列表
|
||||
router.get('/farmers', farmerController.getFarmers);
|
||||
|
||||
// 新增养殖户
|
||||
router.post('/farmers', farmerController.createFarmer);
|
||||
|
||||
// 编辑养殖户
|
||||
router.put('/farmers/:id', farmerController.updateFarmer);
|
||||
|
||||
// 删除养殖户
|
||||
router.delete('/farmers/:id', farmerController.deleteFarmer);
|
||||
|
||||
// 重置养殖户密码
|
||||
router.post('/farmers/:id/reset-password', farmerController.resetFarmerPassword);
|
||||
|
||||
// 获取养殖类型列表
|
||||
router.get('/farm-types', farmerController.getFarmTypes);
|
||||
|
||||
// 获取养殖种类列表
|
||||
router.get('/animal-types', farmerController.getAnimalTypes);
|
||||
|
||||
module.exports = router;
|
||||
@@ -1,12 +1,20 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const governmentController = require('../controllers/governmentController');
|
||||
|
||||
// 人员列表
|
||||
router.get('/', (req, res) => {
|
||||
res.json({
|
||||
code: 200,
|
||||
data: []
|
||||
});
|
||||
});
|
||||
router.get('/', governmentController.getAdminStaff);
|
||||
|
||||
// 新增行政人员
|
||||
router.post('/', governmentController.createAdminStaff);
|
||||
|
||||
// 编辑行政人员
|
||||
router.put('/:id', governmentController.updateAdminStaff);
|
||||
|
||||
// 删除行政人员
|
||||
router.delete('/:id', governmentController.deleteAdminStaff);
|
||||
|
||||
// 重置行政人员密码
|
||||
router.post('/:id/reset-password', governmentController.resetAdminStaffPassword);
|
||||
|
||||
module.exports = router;
|
||||
55
government-backend/scripts/init-admin-user.js
Normal file
55
government-backend/scripts/init-admin-user.js
Normal file
@@ -0,0 +1,55 @@
|
||||
const User = require('../models/User');
|
||||
const bcrypt = require('bcryptjs');
|
||||
|
||||
// 初始化管理员用户
|
||||
async function initAdminUser() {
|
||||
try {
|
||||
console.log('正在初始化管理员用户...');
|
||||
|
||||
// 检查是否已存在管理员用户
|
||||
const existingAdmin = await User.findOne({
|
||||
where: {
|
||||
username: 'admin',
|
||||
role: 'admin'
|
||||
}
|
||||
});
|
||||
|
||||
if (existingAdmin) {
|
||||
console.log('管理员用户已存在,更新密码...');
|
||||
// 加密密码
|
||||
const hashedPassword = await bcrypt.hash('123456', 10);
|
||||
|
||||
// 更新用户密码
|
||||
await existingAdmin.update({
|
||||
password: hashedPassword,
|
||||
status: 'active'
|
||||
});
|
||||
|
||||
console.log('管理员用户密码更新成功');
|
||||
} else {
|
||||
console.log('创建新的管理员用户...');
|
||||
// 加密密码
|
||||
const hashedPassword = await bcrypt.hash('123456', 10);
|
||||
|
||||
// 创建管理员用户
|
||||
await User.create({
|
||||
username: 'admin',
|
||||
password: hashedPassword,
|
||||
role: 'admin',
|
||||
status: 'active'
|
||||
});
|
||||
|
||||
console.log('管理员用户创建成功');
|
||||
}
|
||||
|
||||
console.log('初始化管理员用户完成');
|
||||
} catch (error) {
|
||||
console.error('初始化管理员用户失败:', error);
|
||||
} finally {
|
||||
// 关闭数据库连接
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// 执行初始化
|
||||
initAdminUser();
|
||||
95
government-backend/scripts/syncFarmersModel.js
Normal file
95
government-backend/scripts/syncFarmersModel.js
Normal file
@@ -0,0 +1,95 @@
|
||||
// 数据库模型同步脚本
|
||||
const sequelize = require('../config/database');
|
||||
const Farmer = require('../models/Farmer');
|
||||
|
||||
// 同步数据库模型并添加测试数据
|
||||
async function syncAndSeed() {
|
||||
try {
|
||||
// 同步模型到数据库
|
||||
await sequelize.sync({ alter: true });
|
||||
console.log('数据库模型同步成功');
|
||||
|
||||
// 检查是否已存在测试数据
|
||||
const existingCount = await Farmer.count();
|
||||
|
||||
if (existingCount === 0) {
|
||||
// 添加测试数据
|
||||
const testFarmers = [
|
||||
{
|
||||
account: 'farmer001',
|
||||
nickname: '牛场小王',
|
||||
real_name: '王小明',
|
||||
farm_name: '明辉养殖场',
|
||||
farm_type: '规模',
|
||||
animal_type: '牛',
|
||||
animal_count: 200,
|
||||
address: '内蒙古自治区通辽市科尔沁区',
|
||||
registrar: 'admin',
|
||||
status: 'active'
|
||||
},
|
||||
{
|
||||
account: 'farmer002',
|
||||
nickname: '草原小李',
|
||||
real_name: '李草原',
|
||||
farm_name: '草原牧业',
|
||||
farm_type: '规模',
|
||||
animal_type: '羊',
|
||||
animal_count: 500,
|
||||
address: '内蒙古自治区通辽市开鲁县',
|
||||
registrar: 'admin',
|
||||
status: 'active'
|
||||
},
|
||||
{
|
||||
account: 'farmer003',
|
||||
nickname: '家庭养殖户老张',
|
||||
real_name: '张家庭',
|
||||
farm_name: '张记养殖场',
|
||||
farm_type: '散养',
|
||||
animal_type: '猪',
|
||||
animal_count: 50,
|
||||
address: '内蒙古自治区通辽市扎鲁特旗',
|
||||
registrar: 'admin',
|
||||
status: 'active'
|
||||
},
|
||||
{
|
||||
account: 'farmer004',
|
||||
nickname: '家禽养殖',
|
||||
real_name: '刘家禽',
|
||||
farm_name: '刘家养殖场',
|
||||
farm_type: '规模',
|
||||
animal_type: '鸡',
|
||||
animal_count: 2000,
|
||||
address: '内蒙古自治区通辽市霍林郭勒市',
|
||||
registrar: 'admin',
|
||||
status: 'active'
|
||||
},
|
||||
{
|
||||
account: 'farmer005',
|
||||
nickname: '特种养殖',
|
||||
real_name: '赵特种',
|
||||
farm_name: '特种养殖场',
|
||||
farm_type: '其他',
|
||||
animal_type: '其他',
|
||||
animal_count: 100,
|
||||
address: '内蒙古自治区通辽市库伦旗',
|
||||
registrar: 'admin',
|
||||
status: 'inactive'
|
||||
}
|
||||
];
|
||||
|
||||
await Farmer.bulkCreate(testFarmers);
|
||||
console.log('测试数据添加成功');
|
||||
} else {
|
||||
console.log('已存在测试数据,跳过添加');
|
||||
}
|
||||
|
||||
// 关闭数据库连接
|
||||
await sequelize.close();
|
||||
} catch (error) {
|
||||
console.error('同步数据库模型或添加测试数据失败:', error);
|
||||
// 确保即使出错也关闭连接
|
||||
await sequelize.close();
|
||||
}
|
||||
}
|
||||
|
||||
syncAndSeed();
|
||||
31
government-backend/test-db-connection.js
Normal file
31
government-backend/test-db-connection.js
Normal file
@@ -0,0 +1,31 @@
|
||||
// 测试数据库连接
|
||||
const sequelize = require('./config/database');
|
||||
|
||||
async function testDbConnection() {
|
||||
try {
|
||||
console.log('正在尝试连接数据库...');
|
||||
console.log('连接配置:', {
|
||||
host: sequelize.config.host,
|
||||
port: sequelize.config.port,
|
||||
database: sequelize.config.database,
|
||||
username: sequelize.config.username,
|
||||
dialect: sequelize.config.dialect
|
||||
});
|
||||
|
||||
await sequelize.authenticate();
|
||||
console.log('✅ 数据库连接成功!');
|
||||
|
||||
// 尝试查询数据库版本信息
|
||||
const [results] = await sequelize.query('SELECT VERSION() AS version');
|
||||
console.log('数据库版本:', results[0].version);
|
||||
|
||||
// 关闭连接
|
||||
await sequelize.close();
|
||||
console.log('数据库连接已关闭');
|
||||
} catch (error) {
|
||||
console.error('❌ 数据库连接失败:', error.message);
|
||||
console.error('详细错误:', error);
|
||||
}
|
||||
}
|
||||
|
||||
testDbConnection();
|
||||
50
government-backend/test-personnel-api.js
Normal file
50
government-backend/test-personnel-api.js
Normal file
@@ -0,0 +1,50 @@
|
||||
// 测试行政人员列表接口
|
||||
const axios = require('axios');
|
||||
|
||||
// 政府后端服务地址
|
||||
const BASE_URL = 'http://localhost:5352/api';
|
||||
|
||||
// 测试行政人员列表接口
|
||||
async function testAdminStaffList() {
|
||||
try {
|
||||
// 先登录获取token
|
||||
const loginResponse = await axios.post(`${BASE_URL}/auth/login`, {
|
||||
username: 'admin',
|
||||
password: '123456'
|
||||
});
|
||||
|
||||
const token = loginResponse.data.token;
|
||||
console.log('登录成功,获取到token');
|
||||
|
||||
// 使用token访问行政人员列表接口
|
||||
const response = await axios.get(`${BASE_URL}/personnel`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
console.log('行政人员列表接口测试结果:');
|
||||
console.log(`- 状态码: ${response.status}`);
|
||||
console.log(`- 返回数据结构:`, Object.keys(response.data));
|
||||
console.log(`- 行政人员总数: ${response.data.total}`);
|
||||
console.log(`- 返回的行政人员列表长度: ${response.data.data ? response.data.data.length : 0}`);
|
||||
|
||||
if (response.data.data && response.data.data.length > 0) {
|
||||
console.log(`- 第一条行政人员数据:`, response.data.data[0]);
|
||||
} else {
|
||||
console.log('- 行政人员列表为空');
|
||||
}
|
||||
|
||||
console.log('\n测试完成!');
|
||||
} catch (error) {
|
||||
console.error('测试失败:', error.message);
|
||||
if (error.response) {
|
||||
console.error('错误状态码:', error.response.status);
|
||||
console.error('错误数据:', error.response.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行测试
|
||||
console.log('开始测试行政人员列表接口...');
|
||||
testAdminStaffList();
|
||||
Reference in New Issue
Block a user