12
This commit is contained in:
parent
9f270c3741
commit
c8b7cff7e9
|
|
@ -0,0 +1,102 @@
|
||||||
|
/**
|
||||||
|
* BusinessPage API - 业务介绍页管理 API
|
||||||
|
* @module api/business/businessPage
|
||||||
|
* @description 提供业务介绍页相关接口,包括列表、新增、编辑、删除、状态管理
|
||||||
|
*/
|
||||||
|
import { request, type ApiResponse } from '@/utils/request'
|
||||||
|
import type { PagedRequest, PagedResult, UpdateStatusRequest } from '@/types/common'
|
||||||
|
|
||||||
|
// ==================== 类型定义 ====================
|
||||||
|
|
||||||
|
/** 业务介绍页项 */
|
||||||
|
export interface BusinessPageItem {
|
||||||
|
id: number
|
||||||
|
title: string
|
||||||
|
imageUrl: string
|
||||||
|
hasActionButton: boolean
|
||||||
|
actionButtonText?: string
|
||||||
|
actionButtonLink?: string
|
||||||
|
sort: number
|
||||||
|
status: number
|
||||||
|
statusName: string
|
||||||
|
createTime: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 查询参数 */
|
||||||
|
export interface BusinessPageQuery extends PagedRequest {
|
||||||
|
title?: string
|
||||||
|
status?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 创建请求 */
|
||||||
|
export interface CreateBusinessPageRequest {
|
||||||
|
title: string
|
||||||
|
imageUrl: string
|
||||||
|
hasActionButton: boolean
|
||||||
|
actionButtonText?: string
|
||||||
|
actionButtonLink?: string
|
||||||
|
sort?: number
|
||||||
|
status?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新请求 */
|
||||||
|
export interface UpdateBusinessPageRequest extends CreateBusinessPageRequest {
|
||||||
|
id: number
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== API ====================
|
||||||
|
|
||||||
|
/** 获取业务介绍页列表 */
|
||||||
|
export function getBusinessPageList(params: BusinessPageQuery): Promise<ApiResponse<PagedResult<BusinessPageItem>>> {
|
||||||
|
return request<PagedResult<BusinessPageItem>>({
|
||||||
|
url: '/admin/businessPage/getList',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 创建业务介绍页 */
|
||||||
|
export function createBusinessPage(data: CreateBusinessPageRequest): Promise<ApiResponse<number>> {
|
||||||
|
return request<number>({
|
||||||
|
url: '/admin/businessPage/create',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新业务介绍页 */
|
||||||
|
export function updateBusinessPage(data: UpdateBusinessPageRequest): Promise<ApiResponse<boolean>> {
|
||||||
|
return request<boolean>({
|
||||||
|
url: '/admin/businessPage/update',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除业务介绍页 */
|
||||||
|
export function deleteBusinessPage(id: number): Promise<ApiResponse<boolean>> {
|
||||||
|
return request<boolean>({
|
||||||
|
url: '/admin/businessPage/delete',
|
||||||
|
method: 'post',
|
||||||
|
data: { id }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新业务介绍页状态 */
|
||||||
|
export function updateBusinessPageStatus(data: UpdateStatusRequest): Promise<ApiResponse<boolean>> {
|
||||||
|
return request<boolean>({
|
||||||
|
url: '/admin/businessPage/updateStatus',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新业务介绍页排序 */
|
||||||
|
export function updateBusinessPageSort(data: { id: number; sort: number }): Promise<ApiResponse<boolean>> {
|
||||||
|
return request<boolean>({
|
||||||
|
url: '/admin/businessPage/updateSort',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -67,6 +67,12 @@ export const businessRoutes: RouteRecordRaw[] = [
|
||||||
name: 'Promotion',
|
name: 'Promotion',
|
||||||
component: () => import('@/views/business/content/promotion/index.vue'),
|
component: () => import('@/views/business/content/promotion/index.vue'),
|
||||||
meta: { title: '宣传图管理', permission: 'promotion:view', keepAlive: true }
|
meta: { title: '宣传图管理', permission: 'promotion:view', keepAlive: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'business-page',
|
||||||
|
name: 'BusinessPage',
|
||||||
|
component: () => import('@/views/business/content/business-page/index.vue'),
|
||||||
|
meta: { title: '业务介绍页', permission: 'businessPage:view', keepAlive: true }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,430 @@
|
||||||
|
<template>
|
||||||
|
<div class="business-page-container">
|
||||||
|
<!-- 页面标题和操作栏 -->
|
||||||
|
<el-card class="page-header">
|
||||||
|
<div class="header-content">
|
||||||
|
<div class="header-left">
|
||||||
|
<h2 class="page-title">业务介绍页管理</h2>
|
||||||
|
<span class="page-description">管理小程序业务详情页内容,支持配置长图和操作按钮</span>
|
||||||
|
</div>
|
||||||
|
<div class="header-right">
|
||||||
|
<el-button type="primary" @click="handleAdd">
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
新增介绍页
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 搜索表单 -->
|
||||||
|
<el-card class="search-card">
|
||||||
|
<el-form :model="queryParams" inline>
|
||||||
|
<el-form-item label="标题">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.title"
|
||||||
|
placeholder="请输入标题"
|
||||||
|
clearable
|
||||||
|
@keyup.enter="handleSearch"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态">
|
||||||
|
<DictSelect
|
||||||
|
v-model="queryParams.status"
|
||||||
|
type="common_status"
|
||||||
|
placeholder="请选择状态"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="handleSearch">
|
||||||
|
<el-icon><Search /></el-icon>搜索
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="handleReset">
|
||||||
|
<el-icon><Refresh /></el-icon>重置
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 数据表格 -->
|
||||||
|
<el-card v-loading="state.loading" class="table-card">
|
||||||
|
<el-table :data="state.tableData" row-key="id" stripe>
|
||||||
|
<!-- 图片预览 -->
|
||||||
|
<el-table-column label="图片" width="120" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-image
|
||||||
|
:src="row.imageUrl"
|
||||||
|
:preview-src-list="[row.imageUrl]"
|
||||||
|
fit="cover"
|
||||||
|
style="width: 80px; height: 60px; border-radius: 4px;"
|
||||||
|
preview-teleported
|
||||||
|
>
|
||||||
|
<template #error>
|
||||||
|
<div class="image-error"><el-icon><Picture /></el-icon></div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="title" label="标题" min-width="150" show-overflow-tooltip />
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<el-table-column label="操作按钮" width="200" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<template v-if="row.hasActionButton">
|
||||||
|
<el-tag type="success" size="small">{{ row.actionButtonText || '按钮' }}</el-tag>
|
||||||
|
<div style="font-size: 12px; color: #999; margin-top: 4px;">{{ row.actionButtonLink }}</div>
|
||||||
|
</template>
|
||||||
|
<el-tag v-else type="info" size="small">无按钮</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<!-- 状态 -->
|
||||||
|
<el-table-column label="状态" width="100" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-switch
|
||||||
|
v-model="row.status"
|
||||||
|
:active-value="1"
|
||||||
|
:inactive-value="0"
|
||||||
|
:loading="row._statusLoading"
|
||||||
|
@change="(val: number) => handleStatusChange(row, val)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="sort" label="排序" width="80" align="center" />
|
||||||
|
<el-table-column prop="createTime" label="创建时间" width="180" align="center" />
|
||||||
|
|
||||||
|
<!-- 操作 -->
|
||||||
|
<el-table-column label="操作" width="150" fixed="right" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button type="primary" link size="small" @click="handleEdit(row)">
|
||||||
|
<el-icon><Edit /></el-icon>编辑
|
||||||
|
</el-button>
|
||||||
|
<el-popconfirm
|
||||||
|
title="确定要删除这条业务介绍页吗?"
|
||||||
|
confirm-button-text="确定"
|
||||||
|
cancel-button-text="取消"
|
||||||
|
@confirm="handleDelete(row)"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<el-button type="danger" link size="small">
|
||||||
|
<el-icon><Delete /></el-icon>删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
|
<div class="pagination-wrapper">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="queryParams.pageIndex"
|
||||||
|
v-model:page-size="queryParams.pageSize"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
:total="state.total"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 新增/编辑对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="state.dialogVisible"
|
||||||
|
:title="state.dialogTitle"
|
||||||
|
width="600px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@closed="handleDialogClosed"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="state.formData"
|
||||||
|
:rules="formRules"
|
||||||
|
label-width="110px"
|
||||||
|
label-position="right"
|
||||||
|
>
|
||||||
|
<el-form-item label="标题" prop="title">
|
||||||
|
<el-input v-model="state.formData.title" placeholder="请输入标题" maxlength="100" show-word-limit />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="介绍图片" prop="imageUrl" required>
|
||||||
|
<ImageUpload
|
||||||
|
v-model="state.formData.imageUrl"
|
||||||
|
placeholder="点击上传介绍长图"
|
||||||
|
tip="建议宽度750px,支持 jpg、png 格式"
|
||||||
|
:max-size="10"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="操作按钮" prop="hasActionButton">
|
||||||
|
<el-switch v-model="state.formData.hasActionButton" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<template v-if="state.formData.hasActionButton">
|
||||||
|
<el-form-item label="按钮文字" prop="actionButtonText">
|
||||||
|
<el-input v-model="state.formData.actionButtonText" placeholder="如:立即参与" maxlength="50" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="按钮链接" prop="actionButtonLink">
|
||||||
|
<el-input v-model="state.formData.actionButtonLink" placeholder="如:/pages/assessment/info/index" maxlength="500" />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-form-item label="排序" prop="sort">
|
||||||
|
<el-input-number v-model="state.formData.sort" :min="0" :max="9999" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="状态" prop="status" required>
|
||||||
|
<DictSelect v-model="state.formData.status" type="common_status" placeholder="请选择状态" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="state.dialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="state.formLoading" @click="handleSubmit">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* 业务介绍页管理
|
||||||
|
* @description 管理小程序业务详情页内容
|
||||||
|
*/
|
||||||
|
import { reactive, ref, onMounted } from 'vue'
|
||||||
|
import { Plus, Search, Refresh, Edit, Delete, Picture } from '@element-plus/icons-vue'
|
||||||
|
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
||||||
|
import {
|
||||||
|
getBusinessPageList,
|
||||||
|
createBusinessPage,
|
||||||
|
updateBusinessPage,
|
||||||
|
deleteBusinessPage,
|
||||||
|
updateBusinessPageStatus,
|
||||||
|
type BusinessPageItem,
|
||||||
|
type BusinessPageQuery,
|
||||||
|
type CreateBusinessPageRequest,
|
||||||
|
type UpdateBusinessPageRequest
|
||||||
|
} from '@/api/business/businessPage'
|
||||||
|
import { DictSelect, ImageUpload } from '@/components'
|
||||||
|
|
||||||
|
// ============ Types ============
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
id?: number
|
||||||
|
title: string
|
||||||
|
imageUrl: string
|
||||||
|
hasActionButton: boolean
|
||||||
|
actionButtonText: string
|
||||||
|
actionButtonLink: string
|
||||||
|
sort: number
|
||||||
|
status: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PageState {
|
||||||
|
loading: boolean
|
||||||
|
tableData: (BusinessPageItem & { _statusLoading?: boolean })[]
|
||||||
|
total: number
|
||||||
|
dialogVisible: boolean
|
||||||
|
dialogTitle: string
|
||||||
|
formData: FormData
|
||||||
|
formLoading: boolean
|
||||||
|
isEdit: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ Refs ============
|
||||||
|
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
|
||||||
|
// ============ State ============
|
||||||
|
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
title: '',
|
||||||
|
status: undefined as string | undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
const state = reactive<PageState>({
|
||||||
|
loading: false,
|
||||||
|
tableData: [],
|
||||||
|
total: 0,
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogTitle: '新增介绍页',
|
||||||
|
formData: getDefaultFormData(),
|
||||||
|
formLoading: false,
|
||||||
|
isEdit: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const formRules: FormRules = {
|
||||||
|
title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
|
||||||
|
imageUrl: [{ required: true, message: '请上传介绍图片', trigger: 'change' }],
|
||||||
|
status: [{ required: true, message: '请选择状态', trigger: 'change' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ Helpers ============
|
||||||
|
|
||||||
|
function getDefaultFormData(): FormData {
|
||||||
|
return {
|
||||||
|
title: '',
|
||||||
|
imageUrl: '',
|
||||||
|
hasActionButton: false,
|
||||||
|
actionButtonText: '',
|
||||||
|
actionButtonLink: '',
|
||||||
|
sort: 0,
|
||||||
|
status: '1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ API ============
|
||||||
|
|
||||||
|
async function loadList() {
|
||||||
|
state.loading = true
|
||||||
|
try {
|
||||||
|
const params: BusinessPageQuery = {
|
||||||
|
pageIndex: queryParams.pageIndex,
|
||||||
|
pageSize: queryParams.pageSize
|
||||||
|
}
|
||||||
|
if (queryParams.title) params.title = queryParams.title
|
||||||
|
if (queryParams.status !== undefined && queryParams.status !== '') {
|
||||||
|
params.status = Number(queryParams.status)
|
||||||
|
}
|
||||||
|
const res = await getBusinessPageList(params)
|
||||||
|
if (res.code === 0) {
|
||||||
|
state.tableData = res.data?.list || []
|
||||||
|
state.total = res.data?.total || 0
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message || '获取列表失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error(error instanceof Error ? error.message : '获取列表失败')
|
||||||
|
} finally {
|
||||||
|
state.loading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ Handlers ============
|
||||||
|
|
||||||
|
function handleSearch() { queryParams.pageIndex = 1; loadList() }
|
||||||
|
function handleReset() { queryParams.title = ''; queryParams.status = undefined; queryParams.pageIndex = 1; loadList() }
|
||||||
|
function handleSizeChange(size: number) { queryParams.pageSize = size; queryParams.pageIndex = 1; loadList() }
|
||||||
|
function handleCurrentChange(page: number) { queryParams.pageIndex = page; loadList() }
|
||||||
|
|
||||||
|
function handleAdd() {
|
||||||
|
state.isEdit = false
|
||||||
|
state.dialogTitle = '新增介绍页'
|
||||||
|
state.formData = getDefaultFormData()
|
||||||
|
state.dialogVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleEdit(row: BusinessPageItem) {
|
||||||
|
state.isEdit = true
|
||||||
|
state.dialogTitle = '编辑介绍页'
|
||||||
|
state.formData = {
|
||||||
|
id: row.id,
|
||||||
|
title: row.title || '',
|
||||||
|
imageUrl: row.imageUrl,
|
||||||
|
hasActionButton: row.hasActionButton,
|
||||||
|
actionButtonText: row.actionButtonText || '',
|
||||||
|
actionButtonLink: row.actionButtonLink || '',
|
||||||
|
sort: row.sort,
|
||||||
|
status: String(row.status)
|
||||||
|
}
|
||||||
|
state.dialogVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleStatusChange(row: BusinessPageItem & { _statusLoading?: boolean }, status: number) {
|
||||||
|
row._statusLoading = true
|
||||||
|
try {
|
||||||
|
const res = await updateBusinessPageStatus({ id: row.id, status })
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage.success(status === 1 ? '已启用' : '已禁用')
|
||||||
|
} else {
|
||||||
|
row.status = status === 1 ? 0 : 1
|
||||||
|
throw new Error(res.message || '状态更新失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error(error instanceof Error ? error.message : '状态更新失败')
|
||||||
|
} finally {
|
||||||
|
row._statusLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDelete(row: BusinessPageItem) {
|
||||||
|
try {
|
||||||
|
const res = await deleteBusinessPage(row.id)
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage.success('删除成功')
|
||||||
|
if (state.tableData.length === 1 && queryParams.pageIndex > 1) queryParams.pageIndex--
|
||||||
|
await loadList()
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message || '删除失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error(error instanceof Error ? error.message : '删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSubmit() {
|
||||||
|
if (!formRef.value) return
|
||||||
|
try { await formRef.value.validate() } catch { return }
|
||||||
|
|
||||||
|
state.formLoading = true
|
||||||
|
try {
|
||||||
|
const fd = state.formData
|
||||||
|
const data: CreateBusinessPageRequest | UpdateBusinessPageRequest = {
|
||||||
|
title: fd.title,
|
||||||
|
imageUrl: fd.imageUrl,
|
||||||
|
hasActionButton: fd.hasActionButton,
|
||||||
|
actionButtonText: fd.hasActionButton ? fd.actionButtonText : undefined,
|
||||||
|
actionButtonLink: fd.hasActionButton ? fd.actionButtonLink : undefined,
|
||||||
|
sort: fd.sort,
|
||||||
|
status: Number(fd.status)
|
||||||
|
}
|
||||||
|
let res
|
||||||
|
if (state.isEdit && fd.id) {
|
||||||
|
res = await updateBusinessPage({ ...data, id: fd.id } as UpdateBusinessPageRequest)
|
||||||
|
} else {
|
||||||
|
res = await createBusinessPage(data)
|
||||||
|
}
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage.success(state.isEdit ? '更新成功' : '创建成功')
|
||||||
|
state.dialogVisible = false
|
||||||
|
await loadList()
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message || (state.isEdit ? '更新失败' : '创建失败'))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error(error instanceof Error ? error.message : '操作失败')
|
||||||
|
} finally {
|
||||||
|
state.formLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDialogClosed() {
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
state.formData = getDefaultFormData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ Lifecycle ============
|
||||||
|
|
||||||
|
onMounted(() => { loadList() })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.business-page-container { padding: 0; }
|
||||||
|
.page-header { margin-bottom: 16px; }
|
||||||
|
.header-content { display: flex; justify-content: space-between; align-items: center; }
|
||||||
|
.header-left { display: flex; align-items: baseline; gap: 16px; }
|
||||||
|
.page-title { margin: 0; font-size: 20px; font-weight: 600; color: var(--text-primary, #303133); }
|
||||||
|
.page-description { font-size: 14px; color: var(--text-secondary, #909399); }
|
||||||
|
.search-card { margin-bottom: 16px; }
|
||||||
|
.search-card :deep(.el-card__body) { padding-bottom: 2px; }
|
||||||
|
.table-card { min-height: 400px; }
|
||||||
|
.image-error { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; background: var(--el-fill-color-light); color: var(--el-text-color-placeholder); }
|
||||||
|
.pagination-wrapper { display: flex; justify-content: flex-end; margin-top: 16px; }
|
||||||
|
:deep(.el-table th.el-table__cell) { background-color: var(--bg-light, #f5f7fa); font-weight: 500; }
|
||||||
|
:deep(.el-dialog__body) { padding-top: 20px; }
|
||||||
|
</style>
|
||||||
|
|
@ -10,7 +10,7 @@ import { get } from './request'
|
||||||
* @returns {Promise<Object>}
|
* @returns {Promise<Object>}
|
||||||
*/
|
*/
|
||||||
export function getBusinessDetail(businessId) {
|
export function getBusinessDetail(businessId) {
|
||||||
return get('/business/getDetail', { businessId })
|
return get('/business/getDetail', { id: businessId })
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
"style": {
|
"style": {
|
||||||
"navigationStyle": "custom",
|
"navigationStyle": "custom",
|
||||||
"navigationBarTitleText": "首页",
|
"navigationBarTitleText": "首页",
|
||||||
"enablePullDownRefresh": true
|
"enablePullDownRefresh": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<view class="home-page">
|
<view class="home-page">
|
||||||
<!-- 自定义导航栏 -->
|
<!-- 自定义导航栏 -->
|
||||||
<view class="custom-navbar" :style="navbarStyle">
|
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||||
<view class="navbar-content" :style="{ height: navbarHeight + 'px' }">
|
<view class="navbar-content" :style="{ height: navbarHeight + 'px' }">
|
||||||
<text class="navbar-title">首页</text>
|
<text class="navbar-title">首页</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -11,7 +11,13 @@
|
||||||
<view class="navbar-placeholder" :style="{ height: totalNavbarHeight + 'px' }"></view>
|
<view class="navbar-placeholder" :style="{ height: totalNavbarHeight + 'px' }"></view>
|
||||||
|
|
||||||
<!-- 页面内容 -->
|
<!-- 页面内容 -->
|
||||||
<view class="page-content">
|
<scroll-view
|
||||||
|
class="page-content"
|
||||||
|
scroll-y
|
||||||
|
refresher-enabled
|
||||||
|
:refresher-triggered="isRefreshing"
|
||||||
|
@refresherrefresh="onRefresh"
|
||||||
|
>
|
||||||
<!-- Banner 轮播图 -->
|
<!-- Banner 轮播图 -->
|
||||||
<view class="banner-section" v-if="bannerList.length > 0">
|
<view class="banner-section" v-if="bannerList.length > 0">
|
||||||
<swiper
|
<swiper
|
||||||
|
|
@ -37,28 +43,39 @@
|
||||||
</swiper>
|
</swiper>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 测评入口列表 -->
|
<!-- 专业测评入口 -->
|
||||||
<view class="assessment-section" v-if="assessmentList.length > 0">
|
<view class="assessment-section" v-if="assessmentList.length > 0">
|
||||||
|
<view class="section-header">
|
||||||
|
<view class="section-indicator"></view>
|
||||||
|
<text class="section-title">专业测评</text>
|
||||||
|
</view>
|
||||||
|
<view class="assessment-grid">
|
||||||
<view
|
<view
|
||||||
class="assessment-item"
|
class="assessment-card"
|
||||||
v-for="(item, index) in assessmentList"
|
v-for="(item, index) in assessmentList"
|
||||||
:key="index"
|
:key="index"
|
||||||
@click="handleAssessmentClick(item)"
|
@click="handleAssessmentClick(item)"
|
||||||
>
|
>
|
||||||
<image
|
|
||||||
:src="item.imageUrl"
|
|
||||||
mode="widthFix"
|
|
||||||
class="assessment-image"
|
|
||||||
/>
|
|
||||||
<!-- 即将上线标签 -->
|
<!-- 即将上线标签 -->
|
||||||
<view v-if="item.status === 0" class="coming-soon-tag">
|
<view v-if="item.status === 0" class="coming-soon-tag">
|
||||||
<text>即将上线</text>
|
<text>即将上线</text>
|
||||||
</view>
|
</view>
|
||||||
|
<image
|
||||||
|
:src="item.imageUrl"
|
||||||
|
mode="aspectFit"
|
||||||
|
class="assessment-icon"
|
||||||
|
/>
|
||||||
|
<text class="assessment-name">{{ item.name }}</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 底部宣传长图 -->
|
<!-- 关于我们 - 宣传长图 -->
|
||||||
<view class="promotion-section" v-if="promotionList.length > 0">
|
<view class="promotion-section" v-if="promotionList.length > 0">
|
||||||
|
<view class="section-header">
|
||||||
|
<view class="section-indicator"></view>
|
||||||
|
<text class="section-title">关于我们</text>
|
||||||
|
</view>
|
||||||
<image
|
<image
|
||||||
v-for="(item, index) in promotionList"
|
v-for="(item, index) in promotionList"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
|
@ -75,13 +92,12 @@
|
||||||
|
|
||||||
<!-- 底部安全区域 -->
|
<!-- 底部安全区域 -->
|
||||||
<view class="safe-bottom"></view>
|
<view class="safe-bottom"></view>
|
||||||
</view>
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { onPullDownRefresh } from '@dcloudio/uni-app'
|
|
||||||
import { useUserStore } from '@/store/user.js'
|
import { useUserStore } from '@/store/user.js'
|
||||||
import { useNavbar } from '@/composables/useNavbar.js'
|
import { useNavbar } from '@/composables/useNavbar.js'
|
||||||
import { getBannerList, getAssessmentList, getPromotionList } from '@/api/home.js'
|
import { getBannerList, getAssessmentList, getPromotionList } from '@/api/home.js'
|
||||||
|
|
@ -92,15 +108,12 @@ const { statusBarHeight, navbarHeight, totalNavbarHeight } = useNavbar()
|
||||||
|
|
||||||
// 页面数据
|
// 页面数据
|
||||||
const pageLoading = ref(true)
|
const pageLoading = ref(true)
|
||||||
|
const isRefreshing = ref(false)
|
||||||
const bannerList = ref([])
|
const bannerList = ref([])
|
||||||
const assessmentList = ref([])
|
const assessmentList = ref([])
|
||||||
const promotionList = ref([])
|
const promotionList = ref([])
|
||||||
|
|
||||||
// 导航栏样式
|
// 导航栏样式已直接在模板中绑定
|
||||||
const navbarStyle = computed(() => ({
|
|
||||||
paddingTop: statusBarHeight.value + 'px',
|
|
||||||
height: totalNavbarHeight.value + 'px'
|
|
||||||
}))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载Banner数据
|
* 加载Banner数据
|
||||||
|
|
@ -211,12 +224,13 @@ function handleAssessmentClick(item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下拉刷新
|
* scroll-view 下拉刷新
|
||||||
*/
|
*/
|
||||||
onPullDownRefresh(async () => {
|
async function onRefresh() {
|
||||||
|
isRefreshing.value = true
|
||||||
await initPageData()
|
await initPageData()
|
||||||
uni.stopPullDownRefresh()
|
isRefreshing.value = false
|
||||||
})
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 页面加载
|
* 页面加载
|
||||||
|
|
@ -260,8 +274,9 @@ onMounted(() => {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 页面内容
|
// 页面内容(scroll-view 需要固定高度)
|
||||||
.page-content {
|
.page-content {
|
||||||
|
height: calc(100vh - var(--navbar-height, 0px));
|
||||||
padding-bottom: env(safe-area-inset-bottom);
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -270,11 +285,12 @@ onMounted(() => {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0 $spacing-lg;
|
padding: 0 $spacing-lg;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin-top: $spacing-md;
|
margin-top: $spacing-sm;
|
||||||
|
|
||||||
.banner-swiper {
|
.banner-swiper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 320rpx;
|
// 按设计图比例 750:360 ≈ 2:1,减去两侧 padding 后约 686rpx 宽,高度约 330rpx
|
||||||
|
height: 330rpx;
|
||||||
border-radius: $border-radius-lg;
|
border-radius: $border-radius-lg;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
|
|
@ -286,44 +302,76 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 测评入口
|
// 区块标题
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: $spacing-lg;
|
||||||
|
|
||||||
|
.section-indicator {
|
||||||
|
width: 8rpx;
|
||||||
|
height: 36rpx;
|
||||||
|
background-color: $warning-color;
|
||||||
|
border-radius: $border-radius-xs;
|
||||||
|
margin-right: $spacing-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: $font-size-xl;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
color: $text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测评入口 - 横向排列
|
||||||
.assessment-section {
|
.assessment-section {
|
||||||
padding: $spacing-lg;
|
padding: $spacing-xl $spacing-lg $spacing-lg;
|
||||||
|
|
||||||
.assessment-item {
|
.assessment-grid {
|
||||||
|
display: flex;
|
||||||
|
gap: $spacing-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assessment-card {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-bottom: $spacing-md;
|
display: flex;
|
||||||
border-radius: $border-radius-lg;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
align-items: center;
|
||||||
|
width: 200rpx;
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.assessment-image {
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.coming-soon-tag {
|
.coming-soon-tag {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 20rpx;
|
top: 0;
|
||||||
right: 20rpx;
|
right: 0;
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: $warning-color;
|
||||||
padding: 8rpx 20rpx;
|
padding: 4rpx 16rpx;
|
||||||
border-radius: $border-radius-round;
|
border-radius: 0 $border-radius-xl 0 $border-radius-lg;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
text {
|
text {
|
||||||
font-size: $font-size-xs;
|
font-size: $font-size-xs;
|
||||||
color: $text-white;
|
color: $text-white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.assessment-icon {
|
||||||
|
width: 200rpx;
|
||||||
|
height: 200rpx;
|
||||||
|
border-radius: $border-radius-xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assessment-name {
|
||||||
|
margin-top: $spacing-sm;
|
||||||
|
font-size: $font-size-md;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
color: $text-color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 宣传长图
|
// 关于我们 - 宣传长图
|
||||||
.promotion-section {
|
.promotion-section {
|
||||||
padding: 0 $spacing-lg;
|
padding: $spacing-lg $spacing-lg 0;
|
||||||
|
|
||||||
.promotion-image {
|
.promotion-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user