diff --git a/src/types/auto-components.d.ts b/src/types/auto-components.d.ts index a04c98b3..dfa7c415 100644 --- a/src/types/auto-components.d.ts +++ b/src/types/auto-components.d.ts @@ -58,8 +58,6 @@ declare module '@vue/runtime-core' { ElOption: typeof import('element-plus/es')['ElOption'] ElPagination: typeof import('element-plus/es')['ElPagination'] ElPopover: typeof import('element-plus/es')['ElPopover'] - ElRadio: typeof import('element-plus/es')['ElRadio'] - ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRow: typeof import('element-plus/es')['ElRow'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElSelect: typeof import('element-plus/es')['ElSelect'] diff --git a/src/views/pay/merchant/form.vue b/src/views/pay/merchant/form.vue new file mode 100644 index 00000000..d89fc7a3 --- /dev/null +++ b/src/views/pay/merchant/form.vue @@ -0,0 +1,110 @@ +<template> + <Dialog :title="modelTitle" v-model="modelVisible" width="800"> + <!-- 对话框(添加 / 修改) --> + <el-form ref="formRef" :model="form" :rules="formRules" label-width="80px"> + <el-form-item label="商户全称" prop="name"> + <el-input v-model="form.name" placeholder="请输入商户全称" /> + </el-form-item> + <el-form-item label="商户简称" prop="shortName"> + <el-input v-model="form.shortName" placeholder="请输入商户简称" /> + </el-form-item> + <el-form-item label="开启状态" prop="status"> + <el-select v-model="form.status" placeholder="请选择状态" clearable> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="备注" prop="remark"> + <el-input v-model="form.remark" placeholder="请输入备注" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="modelVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import * as MerchantApi from '@/api/pay/merchant' +import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const modelVisible = ref(false) // 弹窗的是否展示 +const modelTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const form = ref({ + id: undefined, + name: '', + shortName: '', + status: undefined, + remark: '' +}) +const formRules = reactive({ + name: [{ required: true, message: '商户名称不能为空', trigger: 'blur' }], + shortName: [{ required: true, message: '商户简称不能为空', trigger: 'blur' }], + status: [{ required: true, message: '状态不能为空', trigger: 'change' }] +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const openModal = async (type: string, id?: number) => { + modelVisible.value = true + modelTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + form.value = await MerchantApi.getMerchantApi(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ openModal }) // 提供 openModal 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = form.value as unknown as MerchantApi.MerchantVO + if (formType.value === 'create') { + await MerchantApi.createMerchantApi(data) + message.success(t('common.createSuccess')) + } else { + await MerchantApi.updateMerchantApi(data) + message.success(t('common.updateSuccess')) + } + modelVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + form.value = { + id: undefined, + name: '', + shortName: '', + status: undefined, + remark: '' + } + formRef.value?.resetFields() +} +</script> diff --git a/src/views/pay/merchant/index.vue b/src/views/pay/merchant/index.vue index 1ea460ec..e9a9ff30 100644 --- a/src/views/pay/merchant/index.vue +++ b/src/views/pay/merchant/index.vue @@ -1,153 +1,239 @@ <template> - <ContentWrap> - <!-- 列表 --> - <XTable @register="registerTable"> - <template #toolbar_buttons> - <!-- 操作:新增 --> - <XButton + <content-wrap> + <el-form + :model="queryParams" + ref="queryFormRef" + :inline="true" + v-show="showSearch" + label-width="68px" + ><el-form-item label="商户号" prop="no"> + <el-input v-model="queryParams.no" placeholder="请输入商户号" clearable /> + </el-form-item> + <el-form-item label="商户全称" prop="name"> + <el-input v-model="queryParams.name" placeholder="请输入商户全称" clearable /> + </el-form-item> + <el-form-item label="商户简称" prop="shortName"> + <el-input v-model="queryParams.shortName" placeholder="请输入商户简称" clearable /> + </el-form-item> + <el-form-item label="开启状态" prop="status"> + <el-select v-model="queryParams.status" placeholder="字典状态" clearable class="!w-240px"> + <el-option + v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)" + :key="parseInt(dict.value)" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="备注" prop="remark"> + <el-input v-model="queryParams.remark" placeholder="请输入备注" clearable /> + </el-form-item> + <el-form-item label="创建时间" prop="createTime"> + <el-date-picker + v-model="queryParams.createTime" + style="width: 240px" + value-format="YYYY-MM-DD HH:mm:ss" + type="datetimerange" + range-separator="-" + start-placeholder="开始日期" + end-placeholder="结束日期" + /> + </el-form-item> + <el-form-item> + <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button> + <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button> + </el-form-item> + </el-form> + + <!-- 操作工具栏 --> + <el-row :gutter="10" class="mb8"> + <el-col :span="1.5"> + <el-button type="primary" - preIcon="ep:zoom-in" - :title="t('action.add')" + plain + icon="el-icon-plus" + size="small" + @click="openModal('create')" v-hasPermi="['pay:merchant:create']" - @click="handleCreate()" - /> - <!-- 操作:导出 --> - <XButton + >新增</el-button + > + </el-col> + <el-col :span="1.5"> + <el-button type="warning" - preIcon="ep:download" - :title="t('action.export')" + plain + icon="el-icon-download" + size="small" + :loading="exportLoading" + @click="handleExport" v-hasPermi="['pay:merchant:export']" - @click="exportList('商户列表.xls')" - /> - </template> - <template #actionbtns_default="{ row }"> - <!-- 操作:修改 --> - <XTextButton - preIcon="ep:edit" - :title="t('action.edit')" - v-hasPermi="['pay:merchant:update']" - @click="handleUpdate(row.id)" - /> - <!-- 操作:详情 --> - <XTextButton - preIcon="ep:view" - :title="t('action.detail')" - v-hasPermi="['pay:merchant:query']" - @click="handleDetail(row.id)" - /> - <!-- 操作:删除 --> - <XTextButton - preIcon="ep:delete" - :title="t('action.del')" - v-hasPermi="['pay:merchant:delete']" - @click="deleteData(row.id)" - /> - </template> - </XTable> - </ContentWrap> - <XModal v-model="dialogVisible" :title="dialogTitle"> - <!-- 对话框(添加 / 修改) --> - <Form - v-if="['create', 'update'].includes(actionType)" - :schema="allSchemas.formSchema" - :rules="rules" - ref="formRef" - /> - <!-- 对话框(详情) --> - <Descriptions - v-if="actionType === 'detail'" - :schema="allSchemas.detailSchema" - :data="detailData" - /> - <!-- 操作按钮 --> - <template #footer> - <!-- 按钮:保存 --> - <XButton - v-if="['create', 'update'].includes(actionType)" - type="primary" - :title="t('action.save')" - :loading="actionLoading" - @click="submitForm()" + >导出</el-button + > + </el-col> + </el-row> + </content-wrap> + <content-wrap> + <!-- 列表 --> + <el-table v-loading="loading" :data="list"> + <el-table-column label="商户编号" align="center" prop="id" /> + <el-table-column label="商户号" align="center" prop="no" /> + <el-table-column label="商户全称" align="center" prop="name" /> + <el-table-column label="商户简称" align="center" prop="shortName" /> + <el-table-column label="开启状态" align="center" prop="status"> + <template #default="scope"> + <el-switch + v-model="scope.row.status" + :active-value="0" + :inactive-value="1" + @change="handleStatusChange(scope.row)" + /> + </template> + </el-table-column> + <el-table-column label="备注" align="center" prop="remark" /> + <el-table-column + label="创建时间" + :formatter="dateFormatter" + align="center" + prop="createTime" + width="180" /> - <!-- 按钮:关闭 --> - <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" /> - </template> - </XModal> + <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> + <template #default="scope"> + <el-button + link + type="primary" + icon="el-icon-edit" + @click="openModal('update', scope.row.id)" + v-hasPermi="['pay:merchant:update']" + >修改</el-button + > + <el-button + link + type="danger" + icon="el-icon-delete" + @click="handleDelete(scope.row.id)" + v-hasPermi="['pay:merchant:delete']" + >删除</el-button + > + </template> + </el-table-column> + </el-table> + <!-- 分页组件 --> + <pagination + v-show="total > 0" + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + <!-- 表单弹窗:添加/修改 --> + <MerchantForm ref="modalRef" @success="getList" /> + </content-wrap> </template> + <script setup lang="ts" name="Merchant"> -import type { FormExpose } from '@/components/Form' -import { rules, allSchemas } from './merchant.data' +import { DICT_TYPE, getDictOptions } from '@/utils/dict' import * as MerchantApi from '@/api/pay/merchant' - -const { t } = useI18n() // 国际化 +import MerchantForm from './form.vue' +import download from '@/utils/download' +import { dateFormatter } from '@/utils/formatTime' +import { CommonStatusEnum } from '@/utils/constants' const message = useMessage() // 消息弹窗 -// 列表相关的变量 -const [registerTable, { reload, deleteData, exportList }] = useXTable({ - allSchemas: allSchemas, - getListApi: MerchantApi.getMerchantPageApi, - deleteApi: MerchantApi.deleteMerchantApi, - exportListApi: MerchantApi.exportMerchantApi +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + name: '', + shortName: '', + status: undefined, + pageNo: 1, + pageSize: 100 }) +const queryFormRef = ref() // 搜索的表单 +const showSearch = ref(true) +const exportLoading = ref(false) // 导出的加载中 +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await MerchantApi.getMerchantPageApi(queryParams) -// ========== CRUD 相关 ========== -const actionLoading = ref(false) // 遮罩层 -const actionType = ref('') // 操作按钮的类型 -const dialogVisible = ref(false) // 是否显示弹出层 -const dialogTitle = ref('edit') // 弹出层标题 -const formRef = ref<FormExpose>() // 表单 Ref -const detailData = ref() // 详情 Ref - -// 设置标题 -const setDialogTile = (type: string) => { - dialogTitle.value = t('action.' + type) - actionType.value = type - dialogVisible.value = true + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } } -// 新增操作 -const handleCreate = () => { - setDialogTile('create') +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() } -// 修改操作 -const handleUpdate = async (rowId: number) => { - setDialogTile('update') - // 设置数据 - const res = await MerchantApi.getMerchantApi(rowId) - unref(formRef)?.setValues(res) +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() } -// 详情操作 -const handleDetail = async (rowId: number) => { - setDialogTile('detail') - const res = await MerchantApi.getMerchantApi(rowId) - detailData.value = res +/** 添加/修改操作 */ +const modalRef = ref() +const openModal = (type: string, id?: number) => { + modalRef.value.openModal(type, id) } -// 提交按钮 -const submitForm = async () => { - const elForm = unref(formRef)?.getElFormRef() - if (!elForm) return - elForm.validate(async (valid) => { - if (valid) { - actionLoading.value = true - // 提交请求 - try { - const data = unref(formRef)?.formModel as MerchantApi.MerchantVO - if (actionType.value === 'create') { - await MerchantApi.createMerchantApi(data) - message.success(t('common.createSuccess')) - } else { - await MerchantApi.updateMerchantApi(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - } finally { - actionLoading.value = false - // 刷新列表 - await reload() - } - } - }) +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await MerchantApi.deleteMerchantApi(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} } + +// 启用状态修改 +const handleStatusChange = (row: MerchantApi.MerchantVO) => { + let info = row.status === CommonStatusEnum.ENABLE ? '启用' : '停用' + message + .confirm('确认要"' + info + '""' + row.name + '"商户吗?', t('common.reminder')) + .then(async () => { + row.status = + row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.ENABLE : CommonStatusEnum.DISABLE + await MerchantApi.updateMerchantApi(row) + message.success(info + '成功') + // 刷新列表 + getList() + }) + .catch(() => { + row.status = + row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE + }) +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await MerchantApi.exportMerchantApi(queryParams) + download.excel(data, '商户信息.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) </script> diff --git a/src/views/pay/merchant/merchant.data.ts b/src/views/pay/merchant/merchant.data.ts deleted file mode 100644 index e0e0727d..00000000 --- a/src/views/pay/merchant/merchant.data.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas' -const { t } = useI18n() // 国际化 - -// 表单校验 -export const rules = reactive({ - no: [required], - name: [required], - shortName: [required], - status: [required] -}) - -// CrudSchema -const crudSchemas = reactive<VxeCrudSchema>({ - primaryKey: 'id', - primaryType: 'seq', - primaryTitle: '商户编号', - action: true, - columns: [ - { - title: '商户号', - field: 'no', - isSearch: true - }, - { - title: '商户全称', - field: 'code', - isSearch: true - }, - { - title: '商户简称', - field: 'shortName', - isSearch: true - }, - { - title: t('common.status'), - field: 'status', - dictType: DICT_TYPE.COMMON_STATUS, - dictClass: 'number', - isSearch: true - }, - { - title: t('form.remark'), - field: 'remark', - isTable: false, - form: { - component: 'Input', - componentProps: { - type: 'textarea', - rows: 4 - }, - colProps: { - span: 24 - } - } - }, - { - title: t('common.createTime'), - field: 'createTime', - formatter: 'formatDate', - isForm: false, - search: { - show: true, - itemRender: { - name: 'XDataTimePicker' - } - } - } - ] -}) -export const { allSchemas } = useVxeCrudSchemas(crudSchemas)