增加权限审核,限制显示内容,细节优化
This commit is contained in:
@@ -81,7 +81,7 @@ const loading = ref(false)
|
||||
const getCaptcha = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const response = await api.auth.captcha('/captcha/generate')
|
||||
const response = await api.auth.captcha()
|
||||
|
||||
if (response.data.success) {
|
||||
captchaImage.value = response.data.data.image
|
||||
|
||||
@@ -20,16 +20,16 @@
|
||||
<template #title>仪表盘</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item v-if="userStore.isAdmin" index="/products">
|
||||
<el-menu-item v-if="userStore.isSupplier" index="/products">
|
||||
<el-icon><Goods /></el-icon>
|
||||
<template #title>商品管理</template>
|
||||
</el-menu-item>
|
||||
|
||||
<el-menu-item v-if="userStore.isAdmin" index="/orders">
|
||||
<el-menu-item v-if="userStore.isSupplier" index="/orders">
|
||||
<el-icon><List /></el-icon>
|
||||
<template #title>订单管理</template>
|
||||
</el-menu-item>
|
||||
<el-menu-item v-if="userStore.isAdmin" index="/withdrawals">
|
||||
<el-menu-item v-if="userStore.isSupplier" index="/withdrawals">
|
||||
<el-icon><Money /></el-icon>
|
||||
<template #title>提现审批</template>
|
||||
</el-menu-item>
|
||||
@@ -199,6 +199,7 @@ import {
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
import api from '@/utils/api'
|
||||
|
||||
// 组件挂载时不再自动验证token,避免登录后立即触发401错误
|
||||
// token验证交给具体的API调用时处理
|
||||
@@ -228,8 +229,8 @@ const passwordRules = {
|
||||
{ required: true, message: '请输入新密码', trigger: 'blur' },
|
||||
{ min: 6, message: '密码长度不能少于6位', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?&]{6,}$/,
|
||||
message: '密码必须包含大小写字母和数字',
|
||||
pattern: /^(?=.*[a-zA-Z])(?=.*\d)/,
|
||||
message: '密码必须包含字母和数字',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
@@ -320,12 +321,13 @@ const handleChangePassword = async () => {
|
||||
try {
|
||||
await passwordFormRef.value.validate()
|
||||
|
||||
const result = await userStore.changePassword({
|
||||
currentPassword: passwordForm.value.currentPassword,
|
||||
const result = await api.users.changePassword({
|
||||
id: userStore.user.id,
|
||||
oldPassword: passwordForm.value.currentPassword,
|
||||
newPassword: passwordForm.value.newPassword
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
if (result.data.success) {
|
||||
ElMessage.success('密码修改成功')
|
||||
passwordDialogVisible.value = false
|
||||
resetPasswordForm()
|
||||
|
||||
|
||||
@@ -160,11 +160,22 @@ router.beforeEach(async (to, from, next) => {
|
||||
}
|
||||
|
||||
// 检查管理员权限
|
||||
if (to.meta.requiresAdmin && !userStore.isAdmin) {
|
||||
if (!userStore.isSupplier || userStore.isDelete) {
|
||||
ElMessage.error('您没有权限访问此页面')
|
||||
next('/dashboard')
|
||||
return
|
||||
}
|
||||
|
||||
// 检查审核状态
|
||||
if (userStore.audit_status === 'pending') {
|
||||
ElMessage.warning('您的账号审核中,请稍后登录')
|
||||
next('/dashboard')
|
||||
return
|
||||
} else if (userStore.audit_status === 'rejected') {
|
||||
ElMessage.error('您的账号已被拒绝,请联系管理员')
|
||||
next('/dashboard')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 如果已登录用户访问登录页,重定向到仪表盘
|
||||
|
||||
@@ -12,7 +12,12 @@ export const useUserStore = defineStore('user', {
|
||||
|
||||
getters: {
|
||||
isAuthenticated: (state) => !!state.token && !!state.user,
|
||||
isAdmin: (state) => state.user?.role === 'admin'
|
||||
isAdmin: (state) => state.user?.role === 'admin',
|
||||
isSupplier: (state) => state.user?.role === "supplier",
|
||||
isDelete: (state) => state.user?.is_delete === 1,
|
||||
audit_status: (state) => state.user?.audit_status || "pending",
|
||||
|
||||
// isSupplier: (state) => state.user?.user_type === "supplier",
|
||||
},
|
||||
|
||||
actions: {
|
||||
|
||||
@@ -160,7 +160,7 @@ export const createRequest = (baseURL) => {
|
||||
}
|
||||
// 生成不同的实例
|
||||
export const apiRequest = createRequest(import.meta.env.VITE_API_BASE_URL || '/api')
|
||||
export const midRequest = createRequest(import.meta.env.VITE_UPLOAD_BASE_URL || '/mid')
|
||||
export const midRequest = createRequest(import.meta.env.VITE_UPLOAD_BASE_URL || 'http://192.168.0.12:3005/mid')
|
||||
|
||||
|
||||
// API接口定义
|
||||
@@ -170,7 +170,7 @@ const api = {
|
||||
login: (data) => midRequest.post('/auth/login', data),
|
||||
register: (data) => apiRequest.post('/auth/register', data),
|
||||
getCurrentUser: () => apiRequest.get('/auth/me'),
|
||||
changePassword: (data) => apiRequest.put('/auth/change-password', data),
|
||||
// changePassword: (data) => apiRequest.put('/auth/change-password', data),
|
||||
captcha: () => midRequest.get('/captcha/generate'),
|
||||
},
|
||||
|
||||
@@ -184,7 +184,8 @@ const api = {
|
||||
getUserStats: () => apiRequest.get('/users/stats'),
|
||||
getUserGrowthTrend: (params) => apiRequest.get('/users/growth-trend', {params}),
|
||||
getDailyRevenue: (params) => apiRequest.get('/users/daily-revenue', {params}),
|
||||
getAgentOptions: (params) => apiRequest.get('/admin/agents', {params})
|
||||
getAgentOptions: (params) => apiRequest.get('/admin/agents', {params}),
|
||||
changePassword: (data) => apiRequest.put('/users/password', data),
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -265,6 +265,7 @@ import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { ArrowDown } from '@element-plus/icons-vue';
|
||||
import api from '@/utils/api';
|
||||
import { getImageUrl } from '@/utils/config';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const loading = ref(false);
|
||||
@@ -272,6 +273,7 @@ const orders = ref([]);
|
||||
const dialogVisible = ref(false);
|
||||
const deliveryDialogVisible = ref(false);
|
||||
const selectedOrder = ref(null);
|
||||
const user = useUserStore().user;
|
||||
|
||||
const filters = reactive({
|
||||
orderNumber: '',
|
||||
@@ -301,6 +303,7 @@ const loadOrders = async () => {
|
||||
orderNumber: filters.orderNumber,
|
||||
username: filters.username,
|
||||
status: filters.status,
|
||||
shop_name: user.id,
|
||||
};
|
||||
|
||||
if (filters.dateRange && filters.dateRange.length === 2) {
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
size="large"
|
||||
clearable
|
||||
@change="handlePrimaryCategoryChange"
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="category in primaryCategories"
|
||||
@@ -80,6 +81,7 @@
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="category in secondaryCategories"
|
||||
@@ -703,6 +705,9 @@ import MediaUpload from '@/components/MediaUpload.vue'
|
||||
import HorizontalImageDisplay from '@/components/HorizontalImageDisplay.vue'
|
||||
import RichTextEditor from '@/components/RichTextEditor.vue'
|
||||
|
||||
import {useUserStore} from '@/stores/user'
|
||||
import {getImageUrl} from '@/utils/config'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const formRef = ref()
|
||||
@@ -711,6 +716,8 @@ const categories = ref([])
|
||||
|
||||
const newProductId = ref(null)
|
||||
|
||||
const user = useUserStore().user
|
||||
|
||||
// 计算属性:一级分类
|
||||
const primaryCategories = computed(() => {
|
||||
return categories.value.filter(cat => cat.level === 1)
|
||||
@@ -755,7 +762,7 @@ const form = reactive({
|
||||
images: [],
|
||||
videos: [],
|
||||
shop_name: '',
|
||||
shop_avatar: '',
|
||||
shop_avatar: getImageUrl(user.avatar),
|
||||
payment_methods: ['points'],
|
||||
description: '',
|
||||
details: '',
|
||||
@@ -1171,7 +1178,7 @@ const submitForm = async () => {
|
||||
image_url: form.image.replace('https://minio.zrbjr.com', ''), // 前端 image -> 后端 image_url
|
||||
images: JSON.stringify(form.images.map(img => img.replace('https://minio.zrbjr.com', ''))),
|
||||
videos: JSON.stringify(form.videos),
|
||||
shop_name: form.shop_name,
|
||||
shop_name: user.id,
|
||||
shop_avatar: form.shop_avatar,
|
||||
payment_methods: JSON.stringify(form.payment_methods),
|
||||
description: form.description,
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="分类">
|
||||
<el-select v-model="filters.category" placeholder="请选择分类" clearable style="display: inline-block; width: 150px;">
|
||||
<el-select v-model="filters.category" placeholder="请选择分类" clearable style="display: inline-block; width: 150px;" filterable>
|
||||
<el-option
|
||||
v-for="category in categories"
|
||||
:key="category"
|
||||
@@ -67,11 +67,11 @@
|
||||
<span class="rongdou-text">{{ row.rongdou_price || 0 }} 融豆</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="shop_name" label="店家" width="120">
|
||||
<el-table-column prop="shop_name" label="供应商" width="120">
|
||||
<template #default="{ row }">
|
||||
<div class="shop-info">
|
||||
<el-avatar v-if="row.shop_avatar" :src="getImageUrl(row.shop_avatar)" :size="24" />
|
||||
<span>{{ row.shop_name || '平台上架' }}</span>
|
||||
<span>{{ row.provider ? row.provider.username : '平台上架' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -147,11 +147,13 @@ import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, ArrowDown, Setting, Grid } from '@element-plus/icons-vue'
|
||||
import api from '@/utils/api'
|
||||
import { getImageUrl } from '@/utils/config'
|
||||
import {useUserStore} from '@/stores/user'
|
||||
|
||||
const router = useRouter()
|
||||
const loading = ref(false)
|
||||
const products = ref([])
|
||||
const categories = ref([])
|
||||
const user = useUserStore().user
|
||||
|
||||
const filters = reactive({
|
||||
search: '',
|
||||
@@ -170,6 +172,7 @@ const loadProducts = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
shop_name: user.id,
|
||||
page: pagination.value.page,
|
||||
limit: pagination.value.limit,
|
||||
...filters
|
||||
|
||||
@@ -394,8 +394,8 @@ const passwordRules = {
|
||||
{ required: true, message: '请输入新密码', trigger: 'blur' },
|
||||
{ min: 6, max: 20, message: '密码长度在 6 到 20 个字符', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?&]/,
|
||||
message: '密码必须包含大小写字母和数字',
|
||||
pattern: /^(?=.*[a-zA-Z])(?=.*\d)/,
|
||||
message: '密码必须包含字母和数字',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
@@ -488,7 +488,8 @@ const changePassword = async () => {
|
||||
changingPassword.value = true
|
||||
|
||||
await api.users.changePassword({
|
||||
currentPassword: passwordForm.currentPassword,
|
||||
id: userStore.user.id,
|
||||
oldPassword: passwordForm.currentPassword,
|
||||
newPassword: passwordForm.newPassword
|
||||
})
|
||||
|
||||
|
||||
@@ -178,7 +178,8 @@ const loadWithdrawList = async () => {
|
||||
try {
|
||||
const { data } = await api.withdraw.getWithdrawList({
|
||||
page: pagination.page,
|
||||
limit: pagination.limit
|
||||
limit: pagination.limit,
|
||||
user_id: userStore.user.id
|
||||
})
|
||||
withdrawList.value = data.data.withdrawals || []
|
||||
pagination.total = data.data.pagination.total || 0
|
||||
|
||||
Reference in New Issue
Block a user