diff --git a/admin/src/api/config.ts b/admin/src/api/config.ts index 7dac945..c3e2d4c 100644 --- a/admin/src/api/config.ts +++ b/admin/src/api/config.ts @@ -48,3 +48,31 @@ export function getPrivacyPolicy() { export function setPrivacyPolicy(content: string) { return request.post('/admin/config/privacyPolicy', { content }) } + +/** + * 获取会员权益长图 + */ +export function getMemberBenefitsImage() { + return request.get('/admin/config/memberBenefitsImage') +} + +/** + * 设置会员权益长图 + */ +export function setMemberBenefitsImage(imageUrl: string) { + return request.post('/admin/config/memberBenefitsImage', { imageUrl }) +} + +/** + * 获取搜索页Banner + */ +export function getSearchBanner() { + return request.get('/admin/config/searchBanner') +} + +/** + * 设置搜索页Banner + */ +export function setSearchBanner(imageUrl: string) { + return request.post('/admin/config/searchBanner', { imageUrl }) +} diff --git a/admin/src/api/memberTier.ts b/admin/src/api/memberTier.ts new file mode 100644 index 0000000..3003942 --- /dev/null +++ b/admin/src/api/memberTier.ts @@ -0,0 +1,65 @@ +import request from '@/utils/request' + +export interface MemberTier { + id: number + level: number + name: string + badge?: string + price: number + originalPrice: number + discount?: string + benefitsImage?: string + sort: number + status: number + createTime: string + updateTime: string +} + +export interface CreateMemberTierRequest { + level: number + name: string + badge?: string + price: number + originalPrice: number + discount?: string + benefitsImage?: string + sort: number + status: number +} + +export interface UpdateMemberTierRequest extends CreateMemberTierRequest {} + +/** + * 获取会员等级配置列表 + */ +export function getMemberTierList() { + return request.get('/admin/memberTiers') +} + +/** + * 获取单个会员等级配置 + */ +export function getMemberTierById(id: number) { + return request.get(`/admin/memberTiers/${id}`) +} + +/** + * 创建会员等级配置 + */ +export function createMemberTier(data: CreateMemberTierRequest) { + return request.post('/admin/memberTiers', data) +} + +/** + * 更新会员等级配置 + */ +export function updateMemberTier(id: number, data: UpdateMemberTierRequest) { + return request.put(`/admin/memberTiers/${id}`, data) +} + +/** + * 删除会员等级配置 + */ +export function deleteMemberTier(id: number) { + return request.delete(`/admin/memberTiers/${id}`) +} diff --git a/admin/src/router/routes.ts b/admin/src/router/routes.ts index 8afa196..b5ae755 100644 --- a/admin/src/router/routes.ts +++ b/admin/src/router/routes.ts @@ -154,6 +154,12 @@ export const asyncRoutes: RouteRecordRaw[] = [ name: 'Notification', component: () => import('@/views/content/notification.vue'), meta: { title: '系统通知' } + }, + { + path: 'memberTier', + name: 'MemberTier', + component: () => import('@/views/content/memberTier.vue'), + meta: { title: '会员配置' } } ] }, diff --git a/admin/src/views/content/memberTier.vue b/admin/src/views/content/memberTier.vue new file mode 100644 index 0000000..65b597d --- /dev/null +++ b/admin/src/views/content/memberTier.vue @@ -0,0 +1,650 @@ + + + + + diff --git a/admin/src/views/system/config.vue b/admin/src/views/system/config.vue index 9aa23d1..51c6258 100644 --- a/admin/src/views/system/config.vue +++ b/admin/src/views/system/config.vue @@ -34,6 +34,29 @@ + + + + + 保存配置 @@ -94,19 +117,21 @@ import { getUserAgreement, setUserAgreement, getPrivacyPolicy, - setPrivacyPolicy + setPrivacyPolicy, + getSearchBanner, + setSearchBanner } from '@/api/config' import { useUserStore } from '@/stores/user' const userStore = useUserStore() const apiBaseUrl = import.meta.env.VITE_API_BASE_URL || 'http://localhost:5000/api' -// 去掉 /api 后缀获取服务器根地址 const serverUrl = apiBaseUrl.replace(/\/api$/, '') const activeTab = ref('basic') const configForm = ref({ - defaultAvatar: '' + defaultAvatar: '', + searchBanner: '' }) const agreementForm = ref({ @@ -132,10 +157,15 @@ const getFullUrl = (url) => { const loadConfig = async () => { try { - const res = await getDefaultAvatar() - // request 拦截器已经处理了 code,直接返回 data - if (res) { - configForm.value.defaultAvatar = res.avatarUrl || '' + const [avatarRes, bannerRes] = await Promise.all([ + getDefaultAvatar(), + getSearchBanner() + ]) + if (avatarRes) { + configForm.value.defaultAvatar = avatarRes.avatarUrl || '' + } + if (bannerRes) { + configForm.value.searchBanner = bannerRes.imageUrl || '' } } catch (error) { console.error('加载配置失败:', error) @@ -170,6 +200,15 @@ const handleAvatarSuccess = (response) => { } } +const handleBannerSuccess = (response) => { + if (response.code === 0 && response.data) { + configForm.value.searchBanner = response.data.url + ElMessage.success('上传成功') + } else { + ElMessage.error(response.message || '上传失败') + } +} + const beforeAvatarUpload = (file) => { const isImage = file.type.startsWith('image/') const isLt2M = file.size / 1024 / 1024 < 2 @@ -186,18 +225,22 @@ const beforeAvatarUpload = (file) => { } const saveBasicConfig = async () => { - if (!configForm.value.defaultAvatar) { - ElMessage.warning('请先上传默认头像') - return - } - saving.value = true try { - // request 拦截器会处理错误,成功时直接返回 - await setDefaultAvatar(configForm.value.defaultAvatar) - ElMessage.success('保存成功') + const promises = [] + if (configForm.value.defaultAvatar) { + promises.push(setDefaultAvatar(configForm.value.defaultAvatar)) + } + if (configForm.value.searchBanner) { + promises.push(setSearchBanner(configForm.value.searchBanner)) + } + if (promises.length > 0) { + await Promise.all(promises) + ElMessage.success('保存成功') + } else { + ElMessage.warning('请先上传配置图片') + } } catch (error) { - // 错误已在拦截器中处理 console.error('保存失败:', error) } finally { saving.value = false @@ -317,6 +360,47 @@ onMounted(() => { margin: 0; } +.banner-upload { + display: flex; + align-items: flex-start; + gap: 20px; +} + +.banner-uploader { + width: 300px; + height: 128px; +} + +.banner-uploader :deep(.el-upload) { + border: 1px dashed var(--el-border-color); + border-radius: 6px; + cursor: pointer; + position: relative; + overflow: hidden; + transition: var(--el-transition-duration-fast); + width: 300px; + height: 128px; + display: flex; + align-items: center; + justify-content: center; +} + +.banner-uploader :deep(.el-upload:hover) { + border-color: var(--el-color-primary); +} + +.banner-uploader-icon { + font-size: 28px; + color: #8c939d; +} + +.banner-preview { + width: 300px; + height: 128px; + display: block; + object-fit: cover; +} + .agreement-editor { padding: 20px 0; } diff --git a/miniapp/App.vue b/miniapp/App.vue index 8c2b732..201bb88 100644 --- a/miniapp/App.vue +++ b/miniapp/App.vue @@ -1,7 +1,17 @@ - \ No newline at end of file + diff --git a/miniapp/pages/member/index.vue b/miniapp/pages/member/index.vue index cab62e3..350a2bd 100644 --- a/miniapp/pages/member/index.vue +++ b/miniapp/pages/member/index.vue @@ -2,86 +2,80 @@ - - - - - - - - 选择会员等级 - - - - {{ tier.name }} - {{ tier.badge }} - - - ¥ - {{ tier.price }} - - {{ tier.desc }} - - - - - - - - - - 会员权益 - - - {{ benefit.icon }} - - {{ benefit.title }} - {{ benefit.desc }} - - - - - - + + + + + + - - 应付金额: - ¥{{ selectedTierInfo?.price || 0 }} + + + {{ selectedTierInfo?.price || 0 }}元 + {{ selectedTierInfo?.discount || '' }} + + 购买即同意《购买说明》 @@ -90,7 +84,6 @@ -