Commit dc74c1c1 by lijinqi

Merge remote-tracking branch 'origin/develop' into develop

parents e64233b7 e8f5b94f
import request from '@/config/axios'
import type { Dayjs } from 'dayjs';
/** 合作伙伴管理信息 */
export interface Partner {
id: number; // 主键
image: string; // 轮播图地址
information?: string; // 内容
title?: string; // 标题
url: string; // 链接地址
description: string; // 描述内容
orderNum: number; // 排序值
showStatus?: number; // 状态:0-已隐藏,1-已显示
remark: string; // 备注
}
// 合作伙伴管理 API
export const PartnerApi = {
// 查询合作伙伴管理分页
getPartnerPage: async (params: any) => {
return await request.get({ url: `/biz/partner/page`, params })
},
// 查询合作伙伴管理详情
getPartner: async (id: number) => {
return await request.get({ url: `/biz/partner/get?id=` + id })
},
// 新增合作伙伴管理
createPartner: async (data: Partner) => {
return await request.post({ url: `/biz/partner/create`, data })
},
// 修改合作伙伴管理
updatePartner: async (data: Partner) => {
return await request.put({ url: `/biz/partner/update`, data })
},
// 删除合作伙伴管理
deletePartner: async (id: number) => {
return await request.delete({ url: `/biz/partner/delete?id=` + id })
},
/** 批量删除合作伙伴管理 */
deletePartnerList: async (ids: number[]) => {
return await request.delete({ url: `/biz/partner/delete-list?ids=${ids.join(',')}` })
},
// 导出合作伙伴管理 Excel
exportPartner: async (params) => {
return await request.download({ url: `/biz/partner/export-excel`, params })
},
}
\ No newline at end of file
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="展示图地址" prop="images">
<el-upload
v-model:file-list="formData.images"
:action="uploadUrl"
:http-request="httpRequest"
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
multiple
>
<i class="el-icon-plus"></i>
</el-upload>
<!-- 添加预览对话框 -->
<el-dialog v-model="previewVisible" append-to-body>
<img style="width: 100%" :src="dialogImageUrl" alt="Preview Image" />
</el-dialog>
<!-- 添加提示信息 -->
<p class="upload-tips">
请上传 大小不超过 <span class="red-text">5MB</span> 格式为 <span class="red-text">png/jpg/jpeg</span> 的文件
</p>
</el-form-item>
<el-form-item label="内容" prop="information">
<el-input v-model="formData.information" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="标题" prop="title">
<el-input v-model="formData.title" placeholder="请输入标题" />
</el-form-item>
<el-form-item label="链接地址" prop="url">
<el-input v-model="formData.url" placeholder="请输入链接地址" />
</el-form-item>
<el-form-item label="描述内容" prop="description">
<Editor v-model="formData.description" height="150px" />
</el-form-item>
<el-form-item label="排序值" prop="orderNum">
<el-input v-model="formData.orderNum" placeholder="请输入排序值" />
</el-form-item>
<el-form-item label="状态" prop="showStatus">
<el-radio-group v-model="formData.showStatus">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.HOME_INFO_STATUS)"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
<el-button @click="dialogVisible = false">取 消</el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { PartnerApi, Partner } from '@/api/biz/partner'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { useUpload } from '@/components/UploadFile/src/useUpload'
// 添加预览相关的响应式变量
const previewVisible = ref(false)
// 获取上传相关配置
const { uploadUrl, httpRequest } = useUpload()
const dialogImageUrl = ref('')
/** 合作伙伴管理 表单 */
defineOptions({ name: 'PartnerForm' })
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
const formType = ref('') // 表单的类型:create - 新增;update - 修改
const formData = ref({
id: undefined,
images: [],
information: undefined,
title: undefined,
url: undefined,
description: undefined,
orderNum: undefined,
showStatus: undefined,
remark: undefined,
})
const formRules = reactive({
information: [{ required: true, message: '内容不能为空', trigger: 'blur' }],
title: [{ required: true, message: '标题不能为空', trigger: 'blur' }],
showStatus: [{ required: true, message: '状态:0-已隐藏,1-已显示不能为空', trigger: 'blur' }],
orderNum: [{ required: true, message: '排序值不能为空', trigger: 'blur' }]
})
const formRef = ref() // 表单 Ref
// /** 打开弹窗 */
// const open = async (type: string, id?: number) => {
// dialogVisible.value = true
// dialogTitle.value = t('action.' + type)
// formType.value = type
// resetForm()
// // 修改时,设置数据
// if (id) {
// formLoading.value = true
// try {
// formData.value = await PartnerApi.getPartner(id)
// } finally {
// formLoading.value = false
// }
// }
// }
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
// 修改时,设置数据
if (id) {
formLoading.value = true
try {
// formData.value = await IndustryApplicationApi.getIndustryApplication(id)
const data = await PartnerApi.getPartner(id)
// 确保 description 不为 null
if (data.description === null) {
data.description = ''
}
// 将 images 字段转换为 file-list 需要的格式
if (data.images && Array.isArray(data.images)) {
formData.value.images = data.images.map(url => ({ url, name: 'image.jpg' })) // 添加 name 属性
} else {
formData.value.images = []
}
formData.value = { ...data, images: formData.value.images , homeImages: formData.value.homeImages} // 确保 image 是数组
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const submitForm = async () => {
// 校验表单
await formRef.value.validate()
// 提交请求
formLoading.value = true
try {
// 确保只提取真实的 URL,而不是本地的 Blob URL
const imageUrls = formData.value.images
.filter(item => item.url && !item.url.startsWith('blob:')) // 过滤掉 Blob URL
.map(item => item.url);
// 如果还有 Blob URL,说明有文件还未上传完成
const hasBlobUrls = formData.value.images.some(item => item.url && item.url.startsWith('blob:'));
if (hasBlobUrls) {
message.warning('请等待图片上传完成后再提交');
formLoading.value = false;
return;
}
// 构造最终数据
const data = {
...formData.value,
images: imageUrls
};
if (formType.value === 'create') {
await PartnerApi.createPartner(data)
message.success(t('common.createSuccess'))
} else {
await PartnerApi.updatePartner(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
// 发送操作成功的事件
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
images: [],
information: undefined,
title: undefined,
url: undefined,
description: undefined,
orderNum: undefined,
showStatus: undefined,
remark: undefined,
}
formRef.value?.resetFields()
}
// 预览图片
const handlePictureCardPreview = (file) => {
dialogImageUrl.value = file.url
previewVisible.value = true // 使用独立的预览状态
}
// 删除图片
const handleRemove = (file, fileList) => {
// 更新 formData.image 数组
// formData.value.images = fileList.map(item => ({ url: item.url, name: item.name }))
formData.value.images = fileList
}
// 上传成功处理函数
const handleUploadSuccess = (response, file, fileList) => {
// 从响应中提取真实的URL并更新文件对象
if (response && response.data) {
// 根据 useUpload.ts 的实现,可能是 response.data.url 或直接是 response.data
const realUrl = response.data.url || response.data;
if (realUrl) {
file.url = realUrl;
}
}
// 更新 formData.images
formData.value.images = fileList;
}
// 上传失败处理函数
const handleUploadError = (err, file, fileList) => {
message.error('图片上传失败: ' + (err.message || '未知错误'))
}
</script>
<style scoped>.upload-tips {
font-size: 12px;
color: #999;
margin-top: 10px;
}
.red-text {
color: red;
}
</style>
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="内容" prop="information">
<el-input
v-model="queryParams.information"
placeholder="请输入内容"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="标题" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入标题"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="链接地址" prop="url">
<el-input
v-model="queryParams.url"
placeholder="请输入链接地址"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="状态" prop="showStatus">
<el-select v-model="queryParams.showStatus" placeholder="请选择状态" clearable class="!w-200px">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.HOME_INFO_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['biz:partner:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['biz:partner:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
<el-button
type="danger"
plain
:disabled="isEmpty(checkedIds)"
@click="handleDeleteBatch"
v-hasPermi="['biz:partner:delete']"
>
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table
row-key="id"
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
@selection-change="handleRowCheckboxChange"
>
<el-table-column type="selection" width="55" />
<el-table-column label="展示图地址" align="center" prop="images" width="100">
<template #default="scope">
<!-- 只显示第一张图片 -->
<img
v-if="scope.row.images && scope.row.images.length > 0"
:src="scope.row.images[0]"
alt="展示图"
class="h-36px"
/>
<span v-else>暂无图片</span>
</template>
</el-table-column>
<el-table-column label="内容" align="center" prop="information" />
<el-table-column label="标题" align="center" prop="title" />
<el-table-column label="链接地址" align="center" prop="url" />
<el-table-column label="状态" align="center" prop="showStatus">
<template #default="scope">
<dict-tag :type="DICT_TYPE.HOME_INFO_STATUS" :value="scope.row.showStatus" />
</template>
</el-table-column>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" min-width="120px">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['biz:partner:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['biz:partner:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗:添加/修改 -->
<PartnerForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { isEmpty } from '@/utils/is'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { PartnerApi, Partner } from '@/api/biz/partner'
import PartnerForm from './PartnerForm.vue'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
/** 合作伙伴管理 列表 */
defineOptions({ name: 'Partner' })
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中
const list = ref<Partner[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
information: undefined,
title: undefined,
url: undefined,
description: undefined,
orderNum: undefined,
showStatus: undefined,
createTime: [],
remark: undefined,
})
const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) // 导出的加载中
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await PartnerApi.getPartnerPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
// 删除的二次确认
await message.delConfirm()
// 发起删除
await PartnerApi.deletePartner(id)
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
} catch {}
}
/** 批量删除合作伙伴管理 */
const handleDeleteBatch = async () => {
try {
// 删除的二次确认
await message.delConfirm()
await PartnerApi.deletePartnerList(checkedIds.value);
message.success(t('common.delSuccess'))
await getList();
} catch {}
}
const checkedIds = ref<number[]>([])
const handleRowCheckboxChange = (records: Partner[]) => {
checkedIds.value = records.map((item) => item.id);
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
// 导出的二次确认
await message.exportConfirm()
// 发起导出
exportLoading.value = true
const data = await PartnerApi.exportPartner(queryParams)
download.excel(data, '合作伙伴管理.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment