更新
This commit is contained in:
@@ -25,34 +25,33 @@ export const { baseURL, uploadURL } = config[env]
|
||||
* @returns {string} 完整的图片URL
|
||||
*/
|
||||
export const getImageUrl = (imagePath) => {
|
||||
const cleanBaseURL = baseURL.replace(/\/$/, '')
|
||||
// console.log('getImageUrl called with:', imagePath)
|
||||
if (!imagePath) return ''
|
||||
if (imagePath.startsWith('http')) return imagePath
|
||||
console.log(imagePath,'imagePath');
|
||||
|
||||
// 在开发环境下,使用代理路径
|
||||
// 如果图片路径以/uploads开头,直接返回原路径
|
||||
if (imagePath.startsWith('/uploads')) {
|
||||
const cleanBaseURL = baseURL.replace(/\/$/, '')
|
||||
// console.log('Image starts with /uploads, returning original path:', imagePath)
|
||||
return `${imagePath}`
|
||||
}
|
||||
|
||||
// 在开发环境下,也需要根据路径前缀处理
|
||||
if (env === 'development') {
|
||||
// 如果路径已经包含uploads,直接使用
|
||||
if (imagePath.startsWith('/uploads/') || imagePath.startsWith('uploads/')) {
|
||||
const cleanPath = imagePath.startsWith('/') ? imagePath : `/${imagePath}`
|
||||
return cleanPath
|
||||
}
|
||||
// 否则添加uploads前缀
|
||||
return `${cleanBaseURL}${imagePath}`
|
||||
const cleanBaseURL = baseURL.replace(/\/$/, '')
|
||||
const cleanImagePath = imagePath.startsWith('/') ? imagePath : `/${imagePath}`
|
||||
const fullUrl = `${cleanBaseURL}${cleanImagePath}`
|
||||
// console.log('Development environment, returning:', fullUrl)
|
||||
return fullUrl
|
||||
}
|
||||
|
||||
// 生产环境下使用完整URL
|
||||
|
||||
let cleanImagePath
|
||||
const cleanBaseURL = baseURL.replace(/\/$/, '')
|
||||
const cleanImagePath = imagePath.startsWith('/') ? imagePath : `/${imagePath}`
|
||||
const fullUrl = `${cleanBaseURL}${cleanImagePath}`
|
||||
|
||||
// 如果路径已经包含uploads,直接使用
|
||||
if (imagePath.startsWith('/uploads/') || imagePath.startsWith('uploads/')) {
|
||||
cleanImagePath = imagePath.startsWith('/') ? imagePath : `/${imagePath}`
|
||||
} else {
|
||||
// 否则添加uploads前缀
|
||||
cleanImagePath = `/uploads/${imagePath}`
|
||||
}
|
||||
|
||||
return `${cleanBaseURL}${cleanImagePath}`
|
||||
return fullUrl
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,39 +55,17 @@
|
||||
</el-col>
|
||||
|
||||
<!-- 第二行:地区筛选 -->
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6">
|
||||
<el-select
|
||||
v-model="searchForm.city"
|
||||
placeholder="选择城市"
|
||||
clearable
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" style="margin-top: 10px;">
|
||||
<el-cascader
|
||||
v-model="searchForm.region"
|
||||
:options="regionOptions"
|
||||
placeholder="请选择省市区"
|
||||
style="width: 100%"
|
||||
@change="onCityChange"
|
||||
>
|
||||
<el-option label="全部" value="" />
|
||||
<el-option
|
||||
v-for="city in availableCities"
|
||||
:key="city"
|
||||
:label="city"
|
||||
:value="city"
|
||||
/>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6">
|
||||
<el-select
|
||||
v-model="searchForm.district"
|
||||
placeholder="选择地区"
|
||||
:props="{ expandTrigger: 'hover'}"
|
||||
:show-all-levels="true"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
:disabled="!searchForm.city"
|
||||
>
|
||||
<el-option label="全部" value="" />
|
||||
<el-option
|
||||
v-for="district in searchDistricts"
|
||||
:key="district.id"
|
||||
:label="district.district_name"
|
||||
:value="district.id"
|
||||
/>
|
||||
</el-select>
|
||||
@change="handleSearchRegionChange"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
@@ -146,17 +124,11 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
|
||||
<el-table-column label="角色" width="100">
|
||||
<el-table-column label="省份" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.role === 'admin' ? 'danger' : 'primary'" size="small">
|
||||
{{ row.role === 'admin' ? '管理员' : '用户' }}
|
||||
</el-tag>
|
||||
<span>{{ row.province_name || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="城市" width="100">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.city_name || '-' }}</span>
|
||||
@@ -379,38 +351,18 @@
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="城市" prop="city">
|
||||
<el-select
|
||||
v-model="userForm.city"
|
||||
placeholder="请选择城市"
|
||||
<el-col :span="24">
|
||||
<el-form-item label="省市区" prop="region">
|
||||
<el-cascader
|
||||
v-model="userForm.region"
|
||||
:options="regionOptions"
|
||||
placeholder="请选择省市区"
|
||||
style="width: 100%"
|
||||
:props="{ value:'code'}"
|
||||
:show-all-levels="true"
|
||||
clearable
|
||||
@change="onUserFormCityChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="city in availableCities"
|
||||
:key="city"
|
||||
:label="city"
|
||||
:value="city"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="地区" prop="districtId">
|
||||
<el-select
|
||||
v-model="userForm.districtId"
|
||||
placeholder="请选择地区"
|
||||
clearable
|
||||
:disabled="!userForm.city"
|
||||
>
|
||||
<el-option
|
||||
v-for="district in availableDistricts"
|
||||
:key="district.id"
|
||||
:label="district.district_name"
|
||||
:value="district.id"
|
||||
/>
|
||||
</el-select>
|
||||
@change="handleUserFormRegionChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -581,13 +533,13 @@ const dialogVisible = ref(false)
|
||||
const isEdit = ref(false)
|
||||
const users = ref([])
|
||||
const regions = ref([])
|
||||
const cities = ref([])
|
||||
const districts = ref([])
|
||||
const regionOptions = ref([])
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
keyword: '',
|
||||
role: '',
|
||||
region: [],
|
||||
city: '',
|
||||
district: '',
|
||||
sort: 'created_at_desc'
|
||||
@@ -600,33 +552,11 @@ const pagination = reactive({
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 地区相关计算属性
|
||||
const availableCities = computed(() => {
|
||||
const citySet = new Set()
|
||||
;(regions.value || []).forEach(region => {
|
||||
if (region.city_name) {
|
||||
citySet.add(region.city_name)
|
||||
}
|
||||
})
|
||||
return Array.from(citySet).sort()
|
||||
})
|
||||
|
||||
const availableDistricts = computed(() => {
|
||||
if (!userForm.city) return []
|
||||
return (regions.value || []).filter(region => region.city_name === userForm.city)
|
||||
})
|
||||
|
||||
const searchDistricts = computed(() => {
|
||||
if (!searchForm.city) return []
|
||||
return (regions.value || []).filter(region => region.city_name === searchForm.city)
|
||||
})
|
||||
|
||||
// 用户表单
|
||||
const userFormRef = ref()
|
||||
const userForm = reactive({
|
||||
id: null,
|
||||
username: '',
|
||||
|
||||
password: '',
|
||||
role: 'user',
|
||||
accountType: 'normal', // 账户类型:normal-普通商户,virtual-虚拟商户
|
||||
@@ -638,6 +568,7 @@ const userForm = reactive({
|
||||
alipayQr: '',
|
||||
bankCard: '',
|
||||
unionpayQr: '',
|
||||
region: [],
|
||||
city: '',
|
||||
districtId: null,
|
||||
idCardFront: '',
|
||||
@@ -670,6 +601,9 @@ const userRules = computed(() => ({
|
||||
],
|
||||
phone: [
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' }
|
||||
],
|
||||
region: [
|
||||
{ required: true, message: '请选择省市区', trigger: 'change' }
|
||||
]
|
||||
}))
|
||||
|
||||
@@ -704,19 +638,114 @@ const getRegions = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 加载级联选择器数据
|
||||
const loadRegionOptions = async () => {
|
||||
try {
|
||||
// 获取所有省份
|
||||
const provincesResponse = await api.get('/regions/provinces')
|
||||
console.log('获取省份数据:', provincesResponse)
|
||||
if (!provincesResponse.data.success) {
|
||||
throw new Error(provincesResponse.data.message || '获取省份数据失败')
|
||||
}
|
||||
|
||||
regionOptions.value = provincesResponse.data.data || []
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取省市区数据失败:', error)
|
||||
ElMessage.error(error.message || '获取省市区数据失败')
|
||||
|
||||
// 如果API获取失败,使用浙江省数据作为默认数据
|
||||
await loadFallbackRegionData()
|
||||
}
|
||||
}
|
||||
|
||||
// 回退方案:加载浙江省数据
|
||||
const loadFallbackRegionData = async () => {
|
||||
try {
|
||||
const zhejiangResponse = await axios.get('/api/regions/zhejiang')
|
||||
if (zhejiangResponse.data.success) {
|
||||
const zhejiangData = zhejiangResponse.data.data || []
|
||||
// 将浙江省数据转换为级联选择器格式
|
||||
const cityMap = new Map()
|
||||
|
||||
zhejiangData.forEach(item => {
|
||||
if (!cityMap.has(item.city_name)) {
|
||||
cityMap.set(item.city_name, {
|
||||
value: item.city_name,
|
||||
label: item.city_name,
|
||||
children: []
|
||||
})
|
||||
}
|
||||
|
||||
// 添加区县数据
|
||||
if (item.district_name) {
|
||||
cityMap.get(item.city_name).children.push({
|
||||
value: item.district_name,
|
||||
label: item.district_name
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
regionOptions.value = [{
|
||||
value: '浙江省',
|
||||
label: '浙江省',
|
||||
children: Array.from(cityMap.values())
|
||||
}]
|
||||
console.log('已加载浙江省地区数据作为默认选项')
|
||||
} else {
|
||||
throw new Error('获取浙江省数据也失败')
|
||||
}
|
||||
} catch (fallbackError) {
|
||||
console.error('浙江省数据获取失败,使用硬编码数据:', fallbackError)
|
||||
// 最终回退到硬编码数据
|
||||
regionOptions.value = [
|
||||
{
|
||||
value: '浙江省',
|
||||
label: '浙江省',
|
||||
children: [
|
||||
{
|
||||
value: '宁波市',
|
||||
label: '宁波市',
|
||||
children: [
|
||||
{ value: '鄞州区', label: '鄞州区' },
|
||||
{ value: '海曙区', label: '海曙区' },
|
||||
{ value: '江北区', label: '江北区' },
|
||||
{ value: '北仑区', label: '北仑区' }
|
||||
]
|
||||
},
|
||||
{
|
||||
value: '杭州市',
|
||||
label: '杭州市',
|
||||
children: [
|
||||
{ value: '西湖区', label: '西湖区' },
|
||||
{ value: '上城区', label: '上城区' },
|
||||
{ value: '拱墅区', label: '拱墅区' },
|
||||
{ value: '余杭区', label: '余杭区' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// 获取用户列表
|
||||
const fetchUsers = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const [sortField, sortOrder] = searchForm.sort.split('_')
|
||||
|
||||
// 从级联选择器中提取省市区信息
|
||||
const [provinceName, cityName, districtName] = searchForm.region || []
|
||||
|
||||
const params = {
|
||||
page: pagination.page,
|
||||
limit: pagination.limit,
|
||||
search: searchForm.keyword,
|
||||
role: searchForm.role,
|
||||
city: searchForm.city,
|
||||
district: searchForm.district,
|
||||
province: provinceName || '',
|
||||
city: cityName || '',
|
||||
district: districtName || '',
|
||||
sort: sortField,
|
||||
order: sortOrder
|
||||
}
|
||||
@@ -746,6 +775,7 @@ const handleSearch = () => {
|
||||
const handleReset = () => {
|
||||
searchForm.keyword = ''
|
||||
searchForm.role = ''
|
||||
searchForm.region = []
|
||||
searchForm.city = ''
|
||||
searchForm.district = ''
|
||||
searchForm.sort = 'created_at_desc'
|
||||
@@ -753,13 +783,36 @@ const handleReset = () => {
|
||||
fetchUsers()
|
||||
}
|
||||
|
||||
// 搜索表单城市变化处理
|
||||
const onCityChange = () => {
|
||||
searchForm.district = ''
|
||||
// 不再自动触发搜索,需要用户点击搜索按钮
|
||||
// 搜索表单地区变化处理
|
||||
const handleSearchRegionChange = (value) => {
|
||||
console.log('搜索地区变化:', value)
|
||||
if (value && value.length >= 2) {
|
||||
searchForm.city = value[1] // 城市
|
||||
searchForm.district = value.length >= 3 ? value[2] : '' // 区县
|
||||
} else {
|
||||
searchForm.city = ''
|
||||
searchForm.district = ''
|
||||
}
|
||||
}
|
||||
|
||||
// 用户表单城市变化处理
|
||||
// 用户表单地区变化处理
|
||||
const handleUserFormRegionChange = (value) => {
|
||||
console.log('用户表单地区变化:', value)
|
||||
if (value && value.length === 3) {
|
||||
userForm.city = value[1]
|
||||
userForm.districtId = value[2]
|
||||
} else {
|
||||
userForm.city = ''
|
||||
userForm.districtId = null
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索表单城市变化处理(保留兼容性)
|
||||
const onCityChange = () => {
|
||||
searchForm.district = ''
|
||||
}
|
||||
|
||||
// 用户表单城市变化处理(保留兼容性)
|
||||
const onUserFormCityChange = () => {
|
||||
userForm.districtId = null
|
||||
}
|
||||
@@ -793,13 +846,21 @@ const showCreateDialog = () => {
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 显示编辑对话框
|
||||
const showEditDialog = (user) => {
|
||||
isEdit.value = true
|
||||
|
||||
// 构建级联选择器的值 - 直接使用中文名称
|
||||
const regionValue = []
|
||||
if (user.province_name) regionValue.push(user.province_name)
|
||||
if (user.city_name) regionValue.push(user.city_name)
|
||||
if (user.district_name) regionValue.push(user.district_name)
|
||||
|
||||
Object.assign(userForm, {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
|
||||
password: '',
|
||||
role: user.role,
|
||||
accountType: user.is_system_account ? 'virtual' : 'normal',
|
||||
@@ -811,6 +872,7 @@ const showEditDialog = (user) => {
|
||||
alipayQr: user.alipay_qr || '',
|
||||
bankCard: user.bank_card || '',
|
||||
unionpayQr: user.unionpay_qr || '',
|
||||
region: user.region,
|
||||
city: user.city || '',
|
||||
districtId: user.district_id || null,
|
||||
idCardFront: user.id_card_front || '',
|
||||
@@ -827,9 +889,11 @@ const handleSubmit = async () => {
|
||||
|
||||
submitting.value = true
|
||||
|
||||
// 从级联选择器中提取省市区信息
|
||||
const [provinceName, cityName, districtName] = userForm.region || []
|
||||
|
||||
const userData = {
|
||||
username: userForm.username,
|
||||
|
||||
role: userForm.role,
|
||||
isSystemAccount: userForm.accountType === 'virtual', // 转换为后端字段
|
||||
avatar: userForm.avatar,
|
||||
@@ -840,6 +904,8 @@ const handleSubmit = async () => {
|
||||
alipayQr: userForm.alipayQr,
|
||||
bankCard: userForm.bankCard,
|
||||
unionpayQr: userForm.unionpayQr,
|
||||
province: provinceName || '',
|
||||
districtName: districtName || '',
|
||||
city: userForm.city,
|
||||
districtId: userForm.districtId,
|
||||
idCardFront: userForm.idCardFront,
|
||||
@@ -914,6 +980,7 @@ const resetUserForm = () => {
|
||||
alipayQr: '',
|
||||
bankCard: '',
|
||||
unionpayQr: '',
|
||||
region: [],
|
||||
city: '',
|
||||
districtId: null,
|
||||
idCardFront: '',
|
||||
@@ -1028,6 +1095,7 @@ const formatPoints = (points) => {
|
||||
onMounted(() => {
|
||||
fetchUsers()
|
||||
getRegions()
|
||||
loadRegionOptions()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import { resolve } from 'path'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
// base: '/admin',
|
||||
base: '/',
|
||||
base: '/admin',
|
||||
// base: '/',
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
@@ -19,10 +19,10 @@ export default defineConfig({
|
||||
target: 'http://localhost:3000',
|
||||
changeOrigin: true
|
||||
},
|
||||
// '/admin': {
|
||||
// target: 'http://localhost:3000',
|
||||
// changeOrigin: true
|
||||
// },
|
||||
'/admin': {
|
||||
target: 'http://localhost:3000',
|
||||
changeOrigin: true
|
||||
},
|
||||
'/uploads': {
|
||||
target: 'http://localhost:3000',
|
||||
changeOrigin: true
|
||||
|
||||
Reference in New Issue
Block a user