前端安全修复:登录接口改用统一auth接口、Dashboard过滤条件修正、RBAC token处理
This commit is contained in:
parent
6f5d2b8d13
commit
6807cd94a1
|
|
@ -29,10 +29,15 @@ const router = createRouter({
|
||||||
routes
|
routes
|
||||||
})
|
})
|
||||||
|
|
||||||
// 路由守卫
|
// 路由守卫:检查 token
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
// 暂时禁用登录验证
|
if (to.meta.requiresAuth && !localStorage.getItem('token')) {
|
||||||
next()
|
next('/login')
|
||||||
|
} else if (to.path === '/login' && localStorage.getItem('token')) {
|
||||||
|
next('/')
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
/**
|
||||||
|
* 封装 axios,自动附加 Authorization header
|
||||||
|
* 所有需要鉴权的 API 请求统一走这里
|
||||||
|
*/
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
const api = axios.create({
|
||||||
|
baseURL: '/api',
|
||||||
|
timeout: 15000
|
||||||
|
})
|
||||||
|
|
||||||
|
// 请求拦截器:自动附加 token
|
||||||
|
api.interceptors.request.use(
|
||||||
|
(config) => {
|
||||||
|
const token = localStorage.getItem('token')
|
||||||
|
if (token) {
|
||||||
|
config.headers.Authorization = `Bearer ${token}`
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
},
|
||||||
|
(error) => Promise.reject(error)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 响应拦截器:token 过期则跳转登录
|
||||||
|
api.interceptors.response.use(
|
||||||
|
(response) => response,
|
||||||
|
(error) => {
|
||||||
|
if (error.response?.status === 401) {
|
||||||
|
localStorage.removeItem('token')
|
||||||
|
localStorage.removeItem('riderInfo')
|
||||||
|
window.location.href = '/login'
|
||||||
|
}
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default api
|
||||||
|
|
@ -80,7 +80,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import axios from 'axios'
|
import api from '../utils/api'
|
||||||
|
|
||||||
const searchForm = ref({ type: '', status: '' })
|
const searchForm = ref({ type: '', status: '' })
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
|
@ -90,7 +90,7 @@ const viewData = ref({})
|
||||||
const rejectReason = ref('')
|
const rejectReason = ref('')
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const res = await axios.get('http://localhost:3000/api/applications')
|
const res = await api.get('/applications')
|
||||||
if (res.data.success) tableData.value = res.data.data
|
if (res.data.success) tableData.value = res.data.data
|
||||||
}
|
}
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
|
|
@ -102,7 +102,7 @@ const handleSearch = () => {
|
||||||
const handleReset = () => { searchForm.value = { type: '', status: '' }; fetchData() }
|
const handleReset = () => { searchForm.value = { type: '', status: '' }; fetchData() }
|
||||||
const handleView = (row) => { viewData.value = row; dialogVisible.value = true }
|
const handleView = (row) => { viewData.value = row; dialogVisible.value = true }
|
||||||
const handleApprove = async () => {
|
const handleApprove = async () => {
|
||||||
await axios.put(`http://localhost:3000/api/applications/${viewData.value._id}`, { status: '已通过' })
|
await api.put(`/applications/${viewData.value._id}`, { status: '已通过' })
|
||||||
ElMessage.success('已通过')
|
ElMessage.success('已通过')
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
fetchData()
|
fetchData()
|
||||||
|
|
@ -110,7 +110,7 @@ const handleApprove = async () => {
|
||||||
const handleReject = () => { rejectDialogVisible.value = true }
|
const handleReject = () => { rejectDialogVisible.value = true }
|
||||||
const confirmReject = async () => {
|
const confirmReject = async () => {
|
||||||
if (!rejectReason.value.trim()) { ElMessage.warning('请填写拒绝理由'); return }
|
if (!rejectReason.value.trim()) { ElMessage.warning('请填写拒绝理由'); return }
|
||||||
await axios.put(`http://localhost:3000/api/applications/${viewData.value._id}`, { status: '已拒绝', rejectReason: rejectReason.value })
|
await api.put(`/applications/${viewData.value._id}`, { status: '已拒绝', rejectReason: rejectReason.value })
|
||||||
ElMessage.info('已拒绝')
|
ElMessage.info('已拒绝')
|
||||||
rejectDialogVisible.value = false
|
rejectDialogVisible.value = false
|
||||||
rejectReason.value = ''
|
rejectReason.value = ''
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import axios from 'axios'
|
import api from '../utils/api'
|
||||||
|
|
||||||
const searchForm = ref({ type: '', status: '' })
|
const searchForm = ref({ type: '', status: '' })
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
|
@ -105,7 +105,7 @@ const form = ref({ _id: '', type: '', title: '', content: '', applicant: '', app
|
||||||
const rules = { type: [{ required: true, message: '请选择类型', trigger: 'change' }], title: [{ required: true, message: '请输入标题', trigger: 'blur' }] }
|
const rules = { type: [{ required: true, message: '请选择类型', trigger: 'change' }], title: [{ required: true, message: '请输入标题', trigger: 'blur' }] }
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const res = await axios.get('http://localhost:3000/api/approvals')
|
const res = await api.get('/approvals')
|
||||||
if (res.data.success) tableData.value = res.data.data
|
if (res.data.success) tableData.value = res.data.data
|
||||||
}
|
}
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
|
|
@ -118,20 +118,20 @@ const handleReset = () => { searchForm.value = { type: '', status: '' }; fetchDa
|
||||||
const handleAdd = () => { dialogTitle.value = '创建审批'; form.value = { _id: '', type: '', title: '', content: '', applicant: '', approver: '', remark: '', status: '待审批' }; dialogVisible.value = true }
|
const handleAdd = () => { dialogTitle.value = '创建审批'; form.value = { _id: '', type: '', title: '', content: '', applicant: '', approver: '', remark: '', status: '待审批' }; dialogVisible.value = true }
|
||||||
const handleEdit = (row) => { dialogTitle.value = '查看审批'; form.value = { ...row }; dialogVisible.value = true }
|
const handleEdit = (row) => { dialogTitle.value = '查看审批'; form.value = { ...row }; dialogVisible.value = true }
|
||||||
const handleApprove = async (row) => {
|
const handleApprove = async (row) => {
|
||||||
await axios.put(`http://localhost:3000/api/approvals/${row._id}`, { status: '已通过', approver: '管理员' })
|
await api.put(`/approvals/${row._id}`, { status: '已通过', approver: '管理员' })
|
||||||
ElMessage.success('审批通过'); fetchData()
|
ElMessage.success('审批通过'); fetchData()
|
||||||
}
|
}
|
||||||
const handleReject = async (row) => {
|
const handleReject = async (row) => {
|
||||||
await axios.put(`http://localhost:3000/api/approvals/${row._id}`, { status: '已拒绝', approver: '管理员' })
|
await api.put(`/approvals/${row._id}`, { status: '已拒绝', approver: '管理员' })
|
||||||
ElMessage.info('已拒绝'); fetchData()
|
ElMessage.info('已拒绝'); fetchData()
|
||||||
}
|
}
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
await formRef.value.validate()
|
await formRef.value.validate()
|
||||||
if (form.value._id) {
|
if (form.value._id) {
|
||||||
await axios.put(`http://localhost:3000/api/approvals/${form.value._id}`, form.value)
|
await api.put(`/approvals/${form.value._id}`, form.value)
|
||||||
ElMessage.success('修改成功')
|
ElMessage.success('修改成功')
|
||||||
} else {
|
} else {
|
||||||
await axios.post('http://localhost:3000/api/approvals', form.value)
|
await api.post('/approvals', form.value)
|
||||||
ElMessage.success('创建成功')
|
ElMessage.success('创建成功')
|
||||||
}
|
}
|
||||||
dialogVisible.value = false; fetchData()
|
dialogVisible.value = false; fetchData()
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import axios from 'axios'
|
import api from '../utils/api'
|
||||||
|
|
||||||
const searchForm = ref({ type: '', status: '' })
|
const searchForm = ref({ type: '', status: '' })
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
|
@ -105,7 +105,7 @@ const form = ref({ _id: '', type: '', content: '', handler: '', response: '', st
|
||||||
const rules = { type: [{ required: true, message: '请选择类型', trigger: 'change' }], content: [{ required: true, message: '请输入内容', trigger: 'blur' }] }
|
const rules = { type: [{ required: true, message: '请选择类型', trigger: 'change' }], content: [{ required: true, message: '请输入内容', trigger: 'blur' }] }
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const res = await axios.get('http://localhost:3000/api/complaints')
|
const res = await api.get('/complaints')
|
||||||
if (res.data.success) tableData.value = res.data.data
|
if (res.data.success) tableData.value = res.data.data
|
||||||
}
|
}
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
|
|
@ -120,17 +120,17 @@ const handleEdit = (row) => { dialogTitle.value = '处理投诉'; form.value = {
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
await formRef.value.validate()
|
await formRef.value.validate()
|
||||||
if (form.value._id) {
|
if (form.value._id) {
|
||||||
await axios.put(`http://localhost:3000/api/complaints/${form.value._id}`, form.value)
|
await api.put(`/complaints/${form.value._id}`, form.value)
|
||||||
ElMessage.success('处理成功')
|
ElMessage.success('处理成功')
|
||||||
} else {
|
} else {
|
||||||
await axios.post('http://localhost:3000/api/complaints', form.value)
|
await api.post('/complaints', form.value)
|
||||||
ElMessage.success('添加成功')
|
ElMessage.success('添加成功')
|
||||||
}
|
}
|
||||||
dialogVisible.value = false; fetchData()
|
dialogVisible.value = false; fetchData()
|
||||||
}
|
}
|
||||||
const handleDelete = async (row) => {
|
const handleDelete = async (row) => {
|
||||||
await ElMessageBox.confirm('确定删除?', '提示', { type: 'warning' })
|
await ElMessageBox.confirm('确定删除?', '提示', { type: 'warning' })
|
||||||
await axios.delete(`http://localhost:3000/api/complaints/${row._id}`)
|
await api.delete(`/complaints/${row._id}`)
|
||||||
ElMessage.success('删除成功'); fetchData()
|
ElMessage.success('删除成功'); fetchData()
|
||||||
}
|
}
|
||||||
const getStatusType = (status) => ({ '待处理': 'danger', '处理中': 'warning', '已解决': 'success', '已关闭': 'info' }[status] || 'info')
|
const getStatusType = (status) => ({ '待处理': 'danger', '处理中': 'warning', '已解决': 'success', '已关闭': 'info' }[status] || 'info')
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import axios from 'axios'
|
import api from '../utils/api'
|
||||||
|
|
||||||
const searchForm = ref({ type: '', status: '' })
|
const searchForm = ref({ type: '', status: '' })
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
|
@ -114,7 +114,7 @@ const form = ref({ _id: '', type: '', title: '', partyA: '', partyB: '', content
|
||||||
const rules = { type: [{ required: true, message: '请选择类型', trigger: 'change' }], title: [{ required: true, message: '请输入标题', trigger: 'blur' }] }
|
const rules = { type: [{ required: true, message: '请选择类型', trigger: 'change' }], title: [{ required: true, message: '请输入标题', trigger: 'blur' }] }
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const res = await axios.get('http://localhost:3000/api/conflicts')
|
const res = await api.get('/conflicts')
|
||||||
if (res.data.success) tableData.value = res.data.data
|
if (res.data.success) tableData.value = res.data.data
|
||||||
}
|
}
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
|
|
@ -129,17 +129,17 @@ const handleEdit = (row) => { dialogTitle.value = '处理矛盾'; form.value = {
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
await formRef.value.validate()
|
await formRef.value.validate()
|
||||||
if (form.value._id) {
|
if (form.value._id) {
|
||||||
await axios.put(`http://localhost:3000/api/conflicts/${form.value._id}`, form.value)
|
await api.put(`/conflicts/${form.value._id}`, form.value)
|
||||||
ElMessage.success('修改成功')
|
ElMessage.success('修改成功')
|
||||||
} else {
|
} else {
|
||||||
await axios.post('http://localhost:3000/api/conflicts', form.value)
|
await api.post('/conflicts', form.value)
|
||||||
ElMessage.success('登记成功')
|
ElMessage.success('登记成功')
|
||||||
}
|
}
|
||||||
dialogVisible.value = false; fetchData()
|
dialogVisible.value = false; fetchData()
|
||||||
}
|
}
|
||||||
const handleDelete = async (row) => {
|
const handleDelete = async (row) => {
|
||||||
await ElMessageBox.confirm('确定删除?', '提示', { type: 'warning' })
|
await ElMessageBox.confirm('确定删除?', '提示', { type: 'warning' })
|
||||||
await axios.delete(`http://localhost:3000/api/conflicts/${row._id}`)
|
await api.delete(`/conflicts/${row._id}`)
|
||||||
ElMessage.success('删除成功'); fetchData()
|
ElMessage.success('删除成功'); fetchData()
|
||||||
}
|
}
|
||||||
const getStatusType = (status) => ({ '待处理': 'danger', '处理中': 'warning', '已解决': 'success', '已关闭': 'info' }[status] || 'info')
|
const getStatusType = (status) => ({ '待处理': 'danger', '处理中': 'warning', '已解决': 'success', '已关闭': 'info' }[status] || 'info')
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import axios from 'axios'
|
import api from '../utils/api'
|
||||||
|
|
||||||
const searchForm = ref({ name: '', phone: '' })
|
const searchForm = ref({ name: '', phone: '' })
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
|
@ -110,7 +110,7 @@ const rules = {
|
||||||
|
|
||||||
const fetchCustomers = async () => {
|
const fetchCustomers = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get('http://localhost:3000/api/customers')
|
const res = await api.get('/customers')
|
||||||
if (res.data.success) {
|
if (res.data.success) {
|
||||||
tableData.value = res.data.data
|
tableData.value = res.data.data
|
||||||
}
|
}
|
||||||
|
|
@ -154,10 +154,10 @@ const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
await formRef.value.validate()
|
await formRef.value.validate()
|
||||||
if (form.value._id) {
|
if (form.value._id) {
|
||||||
const res = await axios.put(`http://localhost:3000/api/customers/${form.value._id}`, form.value)
|
const res = await api.put(`/customers/${form.value._id}`, form.value)
|
||||||
if (res.data.success) { ElMessage.success('修改成功') }
|
if (res.data.success) { ElMessage.success('修改成功') }
|
||||||
} else {
|
} else {
|
||||||
const res = await axios.post('http://localhost:3000/api/customers', form.value)
|
const res = await api.post('/customers', form.value)
|
||||||
if (res.data.success) { ElMessage.success('添加成功') }
|
if (res.data.success) { ElMessage.success('添加成功') }
|
||||||
}
|
}
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
|
|
@ -168,7 +168,7 @@ const handleSubmit = async () => {
|
||||||
const handleDelete = async (row) => {
|
const handleDelete = async (row) => {
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm('确定要删除这个客户吗?', '提示', { type: 'warning' })
|
await ElMessageBox.confirm('确定要删除这个客户吗?', '提示', { type: 'warning' })
|
||||||
const res = await axios.delete(`http://localhost:3000/api/customers/${row._id}`)
|
const res = await api.delete(`/customers/${row._id}`)
|
||||||
if (res.data.success) { ElMessage.success('删除成功'); fetchCustomers() }
|
if (res.data.success) { ElMessage.success('删除成功'); fetchCustomers() }
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,16 +104,16 @@
|
||||||
<el-table :data="recentPayments" stripe size="small">
|
<el-table :data="recentPayments" stripe size="small">
|
||||||
<el-table-column label="类型" width="80">
|
<el-table-column label="类型" width="80">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag :type="row.type === 'income' ? 'success' : 'danger'" size="small">
|
<el-tag :type="row.type === '收入' ? 'success' : 'danger'" size="small">
|
||||||
{{ row.type === 'income' ? '收入' : '支出' }}
|
{{ row.type === '收入' ? '收入' : '支出' }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="party" label="对方" width="120" />
|
<el-table-column prop="party" label="对方" width="120" />
|
||||||
<el-table-column prop="amount" label="金额" width="100">
|
<el-table-column prop="amount" label="金额" width="100">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<span :style="{ color: row.type === 'income' ? '#52c41a' : '#f5222d', fontWeight: 'bold' }">
|
<span :style="{ color: row.type === '收入' ? '#52c41a' : '#f5222d', fontWeight: 'bold' }">
|
||||||
{{ row.type === 'income' ? '+' : '-' }}¥{{ row.amount }}
|
{{ row.type === '收入' ? '+' : '-' }}¥{{ row.amount }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
@ -173,19 +173,21 @@ const barChartRef = ref(null)
|
||||||
|
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
try {
|
try {
|
||||||
|
const token = localStorage.getItem('token')
|
||||||
|
const headers = token ? { Authorization: `Bearer ${token}` } : {}
|
||||||
// 加载车辆数据
|
// 加载车辆数据
|
||||||
const vehicleRes = await fetch('http://localhost:3000/api/vehicles')
|
const vehicleRes = await fetch('/api/vehicles', { headers })
|
||||||
const vehicleData = await vehicleRes.json()
|
const vehicleData = await vehicleRes.json()
|
||||||
if (vehicleData.success) {
|
if (vehicleData.success) {
|
||||||
const vehicles = vehicleData.data
|
const vehicles = vehicleData.data
|
||||||
stats.value.totalVehicles = vehicles.length
|
stats.value.totalVehicles = vehicles.length
|
||||||
stats.value.availableVehicles = vehicles.filter(v => v.status === '空闲').length
|
stats.value.availableVehicles = vehicles.filter(v => v.status === '空闲').length
|
||||||
stats.value.rentedVehicles = vehicles.filter(v => v.status === '出租中' || v.status === '在租').length
|
stats.value.rentedVehicles = vehicles.filter(v => v.status === '在租').length
|
||||||
stats.value.maintenanceVehicles = vehicles.filter(v => v.status === '维修中').length
|
stats.value.maintenanceVehicles = vehicles.filter(v => v.status === '维修中').length
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载财务数据
|
// 加载财务数据
|
||||||
const financeRes = await fetch('http://localhost:3000/api/finance')
|
const financeRes = await fetch('/api/finance', { headers })
|
||||||
const financeData = await financeRes.json()
|
const financeData = await financeRes.json()
|
||||||
if (financeData.success) {
|
if (financeData.success) {
|
||||||
const list = financeData.data.list || []
|
const list = financeData.data.list || []
|
||||||
|
|
@ -195,8 +197,8 @@ const loadData = async () => {
|
||||||
financeStats.value.totalExpense = summary.totalExpense || 0
|
financeStats.value.totalExpense = summary.totalExpense || 0
|
||||||
financeStats.value.balance = summary.balance || 0
|
financeStats.value.balance = summary.balance || 0
|
||||||
financeStats.value.totalCount = list.length
|
financeStats.value.totalCount = list.length
|
||||||
financeStats.value.incomeCount = list.filter(p => p.type === 'income').length
|
financeStats.value.incomeCount = list.filter(p => p.type === '收入').length
|
||||||
financeStats.value.expenseCount = list.filter(p => p.type === 'expense').length
|
financeStats.value.expenseCount = list.filter(p => p.type === '支出').length
|
||||||
|
|
||||||
// 最近5笔
|
// 最近5笔
|
||||||
recentPayments.value = list.slice(0, 5)
|
recentPayments.value = list.slice(0, 5)
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import axios from 'axios'
|
import api from '../utils/api'
|
||||||
|
|
||||||
const searchForm = ref({ type: '', status: '' })
|
const searchForm = ref({ type: '', status: '' })
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
|
@ -83,7 +83,7 @@ const viewData = ref({})
|
||||||
const result = ref('')
|
const result = ref('')
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const res = await axios.get('http://localhost:3000/api/disputes')
|
const res = await api.get('/disputes')
|
||||||
if (res.data.success) tableData.value = res.data.data
|
if (res.data.success) tableData.value = res.data.data
|
||||||
}
|
}
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
|
|
@ -95,7 +95,7 @@ const handleSearch = () => {
|
||||||
const handleReset = () => { searchForm.value = { type: '', status: '' }; fetchData() }
|
const handleReset = () => { searchForm.value = { type: '', status: '' }; fetchData() }
|
||||||
const handleView = (row) => { viewData.value = row; result.value = row.result || ''; dialogVisible.value = true }
|
const handleView = (row) => { viewData.value = row; result.value = row.result || ''; dialogVisible.value = true }
|
||||||
const handleResolve = async () => {
|
const handleResolve = async () => {
|
||||||
await axios.put(`http://localhost:3000/api/disputes/${viewData.value._id}`, { status: '已解决', result: result.value })
|
await api.put(`/disputes/${viewData.value._id}`, { status: '已解决', result: result.value })
|
||||||
ElMessage.success('已标记为解决')
|
ElMessage.success('已标记为解决')
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
fetchData()
|
fetchData()
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,9 @@ const barChartRef = ref(null)
|
||||||
|
|
||||||
const refresh = async () => {
|
const refresh = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('http://localhost:3000/api/finance')
|
const token = localStorage.getItem('token')
|
||||||
|
const headers = token ? { Authorization: `Bearer ${token}` } : {}
|
||||||
|
const res = await fetch('/api/finance', { headers })
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
payments.value = data.data.list
|
payments.value = data.data.list
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
</el-badge>
|
</el-badge>
|
||||||
<el-dropdown @command="handleCommand">
|
<el-dropdown @command="handleCommand">
|
||||||
<span class="user-info">
|
<span class="user-info">
|
||||||
👤 管理员
|
👤 {{ userName }}
|
||||||
<el-icon><arrow-down /></el-icon>
|
<el-icon><arrow-down /></el-icon>
|
||||||
</span>
|
</span>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
|
|
@ -85,6 +85,10 @@ const route = useRoute()
|
||||||
const activeMenu = computed(() => route.path)
|
const activeMenu = computed(() => route.path)
|
||||||
const notificationCount = ref(2)
|
const notificationCount = ref(2)
|
||||||
|
|
||||||
|
// 读取登录用户信息
|
||||||
|
const riderInfo = JSON.parse(localStorage.getItem('riderInfo') || '{}')
|
||||||
|
const userName = ref(riderInfo.name || '管理员')
|
||||||
|
|
||||||
const pageTitle = computed(() => {
|
const pageTitle = computed(() => {
|
||||||
const titles = {
|
const titles = {
|
||||||
'/': '数据看板',
|
'/': '数据看板',
|
||||||
|
|
@ -104,7 +108,8 @@ const showNotifications = () => {
|
||||||
|
|
||||||
const handleCommand = (command) => {
|
const handleCommand = (command) => {
|
||||||
if (command === 'logout') {
|
if (command === 'logout') {
|
||||||
localStorage.removeItem('isLoggedIn')
|
localStorage.removeItem('token')
|
||||||
|
localStorage.removeItem('riderInfo')
|
||||||
window.location.href = '/login'
|
window.location.href = '/login'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,10 @@
|
||||||
<el-input v-model="loginForm.password" type="password" placeholder="请输入密码" show-password />
|
<el-input v-model="loginForm.password" type="password" placeholder="请输入密码" show-password />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" style="width: 100%;" @click="handleLogin">登录</el-button>
|
<el-button type="primary" style="width: 100%;" :loading="loading" @click="handleLogin">登录</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div class="tips">演示账号: admin / admin</div>
|
<div class="tips">演示账号: admin / admin123</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -29,6 +29,7 @@ import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const formRef = ref(null)
|
const formRef = ref(null)
|
||||||
|
const loading = ref(false)
|
||||||
const loginForm = ref({ username: '', password: '' })
|
const loginForm = ref({ username: '', password: '' })
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
|
|
@ -36,18 +37,41 @@ const rules = {
|
||||||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
|
password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleLogin = () => {
|
const handleLogin = async () => {
|
||||||
formRef.value.validate((valid) => {
|
const valid = await formRef.value.validate().catch(() => false)
|
||||||
if (valid) {
|
if (!valid) return
|
||||||
if (loginForm.value.username === 'admin' && loginForm.value.password === 'admin') {
|
|
||||||
ElMessage.success('登录成功!')
|
loading.value = true
|
||||||
localStorage.setItem('isLoggedIn', 'true')
|
try {
|
||||||
router.push('/')
|
const res = await fetch('/api/auth/login', {
|
||||||
} else {
|
method: 'POST',
|
||||||
ElMessage.error('用户名或密码错误')
|
headers: { 'Content-Type': 'application/json' },
|
||||||
}
|
body: JSON.stringify(loginForm.value)
|
||||||
|
})
|
||||||
|
const data = await res.json()
|
||||||
|
|
||||||
|
if (data.success) {
|
||||||
|
localStorage.setItem('token', data.data.token)
|
||||||
|
localStorage.setItem('userInfo', JSON.stringify({
|
||||||
|
id: data.data.id,
|
||||||
|
username: data.data.username,
|
||||||
|
name: data.data.name,
|
||||||
|
type: data.data.type,
|
||||||
|
role: data.data.role,
|
||||||
|
roleLabel: data.data.roleLabel,
|
||||||
|
permissions: data.data.permissions
|
||||||
|
}))
|
||||||
|
localStorage.setItem('permissions', JSON.stringify(data.data.permissions))
|
||||||
|
ElMessage.success('登录成功!')
|
||||||
|
router.push('/')
|
||||||
|
} else {
|
||||||
|
ElMessage.error(data.message || '登录失败')
|
||||||
}
|
}
|
||||||
})
|
} catch (e) {
|
||||||
|
ElMessage.error('网络错误,请检查后端服务是否启动')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import axios from 'axios'
|
import api from '../utils/api'
|
||||||
|
|
||||||
const searchForm = ref({ orderNumber: '', status: '' })
|
const searchForm = ref({ orderNumber: '', status: '' })
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
|
@ -150,15 +150,15 @@ const rules = {
|
||||||
|
|
||||||
const fetchOrders = async () => {
|
const fetchOrders = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get('http://localhost:3000/api/orders')
|
const res = await api.get('/orders')
|
||||||
if (res.data.success) tableData.value = res.data.data
|
if (res.data.success) tableData.value = res.data.data
|
||||||
} catch { ElMessage.error('获取订单列表失败') }
|
} catch { ElMessage.error('获取订单列表失败') }
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchOptions = async () => {
|
const fetchOptions = async () => {
|
||||||
const [cRes, vRes] = await Promise.all([
|
const [cRes, vRes] = await Promise.all([
|
||||||
axios.get('http://localhost:3000/api/customers'),
|
api.get('/customers'),
|
||||||
axios.get('http://localhost:3000/api/vehicles')
|
api.get('/vehicles')
|
||||||
])
|
])
|
||||||
if (cRes.data.success) customers.value = cRes.data.data
|
if (cRes.data.success) customers.value = cRes.data.data
|
||||||
if (vRes.data.success) vehicles.value = vRes.data.data.filter(v => v.status === '空闲')
|
if (vRes.data.success) vehicles.value = vRes.data.data.filter(v => v.status === '空闲')
|
||||||
|
|
@ -195,10 +195,10 @@ const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
await formRef.value.validate()
|
await formRef.value.validate()
|
||||||
if (form.value._id) {
|
if (form.value._id) {
|
||||||
const res = await axios.put(`http://localhost:3000/api/orders/${form.value._id}`, form.value)
|
const res = await api.put(`/orders/${form.value._id}`, form.value)
|
||||||
if (res.data.success) ElMessage.success('修改成功')
|
if (res.data.success) ElMessage.success('修改成功')
|
||||||
} else {
|
} else {
|
||||||
const res = await axios.post('http://localhost:3000/api/orders', form.value)
|
const res = await api.post('/orders', form.value)
|
||||||
if (res.data.success) ElMessage.success('创建成功')
|
if (res.data.success) ElMessage.success('创建成功')
|
||||||
}
|
}
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
|
|
@ -209,7 +209,7 @@ const handleSubmit = async () => {
|
||||||
const handleDelete = async (row) => {
|
const handleDelete = async (row) => {
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm('确定要删除这个订单吗?', '提示', { type: 'warning' })
|
await ElMessageBox.confirm('确定要删除这个订单吗?', '提示', { type: 'warning' })
|
||||||
const res = await axios.delete(`http://localhost:3000/api/orders/${row._id}`)
|
const res = await api.delete(`/orders/${row._id}`)
|
||||||
if (res.data.success) { ElMessage.success('删除成功'); fetchOrders() }
|
if (res.data.success) { ElMessage.success('删除成功'); fetchOrders() }
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import axios from 'axios'
|
import api from '../utils/api'
|
||||||
|
|
||||||
const searchForm = ref({ type: '', status: '' })
|
const searchForm = ref({ type: '', status: '' })
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
|
@ -109,7 +109,7 @@ const form = ref({ _id: '', type: '', amount: 0, method: '', account: '', operat
|
||||||
const rules = { type: [{ required: true, message: '请选择类型', trigger: 'change' }], amount: [{ required: true, message: '请输入金额', trigger: 'blur' }] }
|
const rules = { type: [{ required: true, message: '请选择类型', trigger: 'change' }], amount: [{ required: true, message: '请输入金额', trigger: 'blur' }] }
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const res = await axios.get('http://localhost:3000/api/payments')
|
const res = await api.get('/payments')
|
||||||
if (res.data.success) tableData.value = res.data.data
|
if (res.data.success) tableData.value = res.data.data
|
||||||
}
|
}
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
|
|
@ -122,16 +122,16 @@ const handleReset = () => { searchForm.value = { type: '', status: '' }; fetchDa
|
||||||
const handleAdd = () => { dialogTitle.value = '创建打款'; form.value = { _id: '', type: '', amount: 0, method: '', account: '', operator: '', remark: '', status: '待打款' }; dialogVisible.value = true }
|
const handleAdd = () => { dialogTitle.value = '创建打款'; form.value = { _id: '', type: '', amount: 0, method: '', account: '', operator: '', remark: '', status: '待打款' }; dialogVisible.value = true }
|
||||||
const handleEdit = (row) => { dialogTitle.value = '编辑打款'; form.value = { ...row }; dialogVisible.value = true }
|
const handleEdit = (row) => { dialogTitle.value = '编辑打款'; form.value = { ...row }; dialogVisible.value = true }
|
||||||
const handleProcess = async (row) => {
|
const handleProcess = async (row) => {
|
||||||
await axios.put(`http://localhost:3000/api/payments/${row._id}`, { status: '已打款' })
|
await api.put(`/payments/${row._id}`, { status: '已打款' })
|
||||||
ElMessage.success('打款成功'); fetchData()
|
ElMessage.success('打款成功'); fetchData()
|
||||||
}
|
}
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
await formRef.value.validate()
|
await formRef.value.validate()
|
||||||
if (form.value._id) {
|
if (form.value._id) {
|
||||||
await axios.put(`http://localhost:3000/api/payments/${form.value._id}`, form.value)
|
await api.put(`/payments/${form.value._id}`, form.value)
|
||||||
ElMessage.success('修改成功')
|
ElMessage.success('修改成功')
|
||||||
} else {
|
} else {
|
||||||
await axios.post('http://localhost:3000/api/payments', form.value)
|
await api.post('/payments', form.value)
|
||||||
ElMessage.success('创建成功')
|
ElMessage.success('创建成功')
|
||||||
}
|
}
|
||||||
dialogVisible.value = false; fetchData()
|
dialogVisible.value = false; fetchData()
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import axios from 'axios'
|
import api from '../utils/api'
|
||||||
|
|
||||||
const searchForm = ref({ name: '', approvalStatus: '' })
|
const searchForm = ref({ name: '', approvalStatus: '' })
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
|
|
@ -132,7 +132,7 @@ const dialogVisible = ref(false)
|
||||||
const viewData = ref({})
|
const viewData = ref({})
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const res = await axios.get('http://localhost:3000/api/stores')
|
const res = await api.get('/stores')
|
||||||
if (res.data.success) tableData.value = res.data.data
|
if (res.data.success) tableData.value = res.data.data
|
||||||
}
|
}
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
|
|
@ -150,7 +150,7 @@ const rejectReason = ref('')
|
||||||
const showRejectDialog = ref(false)
|
const showRejectDialog = ref(false)
|
||||||
|
|
||||||
const handleApprove = async () => {
|
const handleApprove = async () => {
|
||||||
await axios.put(`http://localhost:3000/api/stores/${viewData.value._id}`, { approvalStatus: '已通过' })
|
await api.put(`/stores/${viewData.value._id}`, { approvalStatus: '已通过' })
|
||||||
ElMessage.success('已通过审批')
|
ElMessage.success('已通过审批')
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
fetchData()
|
fetchData()
|
||||||
|
|
@ -160,7 +160,7 @@ const confirmReject = async () => {
|
||||||
ElMessage.warning('请填写拒绝理由')
|
ElMessage.warning('请填写拒绝理由')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
await axios.put(`http://localhost:3000/api/stores/${viewData.value._id}`, { approvalStatus: '已拒绝', rejectReason: rejectReason.value })
|
await api.put(`/stores/${viewData.value._id}`, { approvalStatus: '已拒绝', rejectReason: rejectReason.value })
|
||||||
ElMessage.info('已拒绝')
|
ElMessage.info('已拒绝')
|
||||||
showRejectDialog.value = false
|
showRejectDialog.value = false
|
||||||
rejectReason.value = ''
|
rejectReason.value = ''
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import axios from 'axios'
|
import api from '../utils/api'
|
||||||
import { exportExcel, formatDate } from '../utils'
|
import { exportExcel, formatDate } from '../utils'
|
||||||
|
|
||||||
const searchForm = ref({ vehicleId: '', status: '' })
|
const searchForm = ref({ vehicleId: '', status: '' })
|
||||||
|
|
@ -128,7 +128,7 @@ const rules = {
|
||||||
|
|
||||||
const fetchVehicles = async () => {
|
const fetchVehicles = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get('http://localhost:3000/api/vehicles')
|
const res = await api.get('/vehicles')
|
||||||
if (res.data.success) tableData.value = res.data.data
|
if (res.data.success) tableData.value = res.data.data
|
||||||
} catch { ElMessage.error('获取车辆列表失败') }
|
} catch { ElMessage.error('获取车辆列表失败') }
|
||||||
}
|
}
|
||||||
|
|
@ -158,10 +158,10 @@ const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
await formRef.value.validate()
|
await formRef.value.validate()
|
||||||
if (form.value._id) {
|
if (form.value._id) {
|
||||||
const res = await axios.put(`http://localhost:3000/api/vehicles/${form.value._id}`, form.value)
|
const res = await api.put(`/vehicles/${form.value._id}`, form.value)
|
||||||
if (res.data.success) ElMessage.success('修改成功')
|
if (res.data.success) ElMessage.success('修改成功')
|
||||||
} else {
|
} else {
|
||||||
const res = await axios.post('http://localhost:3000/api/vehicles', form.value)
|
const res = await api.post('/vehicles', form.value)
|
||||||
if (res.data.success) ElMessage.success('添加成功')
|
if (res.data.success) ElMessage.success('添加成功')
|
||||||
}
|
}
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
|
|
@ -172,7 +172,7 @@ const handleSubmit = async () => {
|
||||||
const handleDelete = async (row) => {
|
const handleDelete = async (row) => {
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm('确定要删除这辆车吗?', '提示', { type: 'warning' })
|
await ElMessageBox.confirm('确定要删除这辆车吗?', '提示', { type: 'warning' })
|
||||||
const res = await axios.delete(`http://localhost:3000/api/vehicles/${row._id}`)
|
const res = await api.delete(`/vehicles/${row._id}`)
|
||||||
if (res.data.success) { ElMessage.success('删除成功'); fetchVehicles() }
|
if (res.data.success) { ElMessage.success('删除成功'); fetchVehicles() }
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,26 @@
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
// https://vite.dev/config/
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [vue()],
|
plugins: [vue()],
|
||||||
|
server: {
|
||||||
|
port: 5173,
|
||||||
|
host: '0.0.0.0',
|
||||||
|
allowedHosts: ['51bike.online', 'admin.51bike.online', '43.156.200.173'],
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://localhost:3000',
|
||||||
|
changeOrigin: true,
|
||||||
|
// 显式确保 Authorization header 被转发(Vite 默认会转发,此处明确声明以防被代理中间件清除)
|
||||||
|
configure: (proxy) => {
|
||||||
|
proxy.on('proxyReq', (proxyReq) => {
|
||||||
|
// 确保 Authorization header 被传递到后端
|
||||||
|
if (proxyReq.getHeader('authorization')) {
|
||||||
|
proxyReq.setHeader('authorization', proxyReq.getHeader('authorization'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue